Merge tag 'mac80211-next-for-davem-2015-01-15' of git://git.kernel.org/pub/scm/linux...
authorDavid S. Miller <davem@davemloft.net>
Fri, 16 Jan 2015 00:16:56 +0000 (19:16 -0500)
committerDavid S. Miller <davem@davemloft.net>
Fri, 16 Jan 2015 00:16:56 +0000 (19:16 -0500)
Here's a big pile of changes for this round.

We have
 * a lot of regulatory code changes to deal with the
   way newer Intel devices handle this
 * a change to drop packets while disconnecting from
   an AP instead of trying to wait for them
 * a new attempt at improving the tailroom accounting
   to not kick in too much for performance reasons
 * improvements in wireless link statistics
 * many other small improvements and small fixes that
   didn't seem necessary for 3.19 (e.g. in hwsim which
   is testing only code)

Conflicts:
drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c

Minor overlapping changes.

Signed-off-by: David S. Miller <davem@davemloft.net>
72 files changed:
Documentation/DocBook/80211.tmpl
Documentation/kernel-parameters.txt
Documentation/rfkill.txt
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath9k/link.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/cmd.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/ath/wil6210/wmi.c
drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/cw1200/main.c
drivers/net/wireless/cw1200/sta.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/uap_event.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/p54/eeprom.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/ti/wl1251/main.c
drivers/net/wireless/ti/wlcore/main.c
drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
drivers/staging/wlan-ng/cfg80211.c
include/net/cfg80211.h
include/net/mac80211.h
include/net/regulatory.h
include/uapi/linux/nl80211.h
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs.c
net/mac80211/driver-ops.h
net/mac80211/ethtool.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/main.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/pm.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel.h
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/spectmgmt.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tdls.c
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/vht.c
net/wireless/core.c
net/wireless/core.h
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/reg.c
net/wireless/reg.h
net/wireless/scan.c
net/wireless/trace.h
net/wireless/wext-compat.c

index d9b9416..49b8b89 100644 (file)
 !Finclude/net/cfg80211.h cfg80211_beacon_data
 !Finclude/net/cfg80211.h cfg80211_ap_settings
 !Finclude/net/cfg80211.h station_parameters
-!Finclude/net/cfg80211.h station_info_flags
 !Finclude/net/cfg80211.h rate_info_flags
 !Finclude/net/cfg80211.h rate_info
 !Finclude/net/cfg80211.h station_info
index 4df73da..cdb815e 100644 (file)
@@ -3206,6 +3206,18 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
        retain_initrd   [RAM] Keep initrd memory after extraction
 
+       rfkill.default_state=
+               0       "airplane mode".  All wifi, bluetooth, wimax, gps, fm,
+                       etc. communication is blocked by default.
+               1       Unblocked.
+
+       rfkill.master_switch_mode=
+               0       The "airplane mode" button does nothing.
+               1       The "airplane mode" button toggles between everything
+                       blocked and the previous configuration.
+               2       The "airplane mode" button toggles between everything
+                       blocked and everything unblocked.
+
        rhash_entries=  [KNL,NET]
                        Set number of hash buckets for route cache
 
index 427e897..2ee6ef9 100644 (file)
@@ -25,6 +25,9 @@ whether they can be changed or not:
  - soft block: writable radio block (need not be readable) that is set by
                the system software.
 
+The rfkill subsystem has two parameters, rfkill.default_state and
+rfkill.master_switch_mode, which are documented in kernel-parameters.txt.
+
 
 2. Implementation details
 
index c400567..2619db1 100644 (file)
@@ -2871,6 +2871,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
        int bit;
        u32 vdev_param;
 
+       vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
+
        mutex_lock(&ar->conf_mutex);
 
        memset(arvif, 0, sizeof(*arvif));
@@ -5024,7 +5026,6 @@ int ath10k_mac_register(struct ath10k *ar)
        ar->hw->flags = IEEE80211_HW_SIGNAL_DBM |
                        IEEE80211_HW_SUPPORTS_PS |
                        IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
-                       IEEE80211_HW_SUPPORTS_UAPSD |
                        IEEE80211_HW_MFP_CAPABLE |
                        IEEE80211_HW_REPORTS_TX_ACK_STATUS |
                        IEEE80211_HW_HAS_RATE_CONTROL |
index c0f3e4d..721631c 100644 (file)
@@ -1344,11 +1344,11 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
                rx_clear_count -= ar->survey_last_rx_clear_count;
 
                survey = &ar->survey[idx];
-               survey->channel_time = WMI_CHAN_INFO_MSEC(cycle_count);
-               survey->channel_time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count);
+               survey->time = WMI_CHAN_INFO_MSEC(cycle_count);
+               survey->time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count);
                survey->noise = noise_floor;
-               survey->filled = SURVEY_INFO_CHANNEL_TIME |
-                                SURVEY_INFO_CHANNEL_TIME_RX |
+               survey->filled = SURVEY_INFO_TIME |
+                                SURVEY_INFO_TIME_RX |
                                 SURVEY_INFO_NOISE_DBM;
        }
 
index 19eab2a..3b4a646 100644 (file)
@@ -672,10 +672,10 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
        spin_lock_bh(&common->cc_lock);
        ath_hw_cycle_counters_update(common);
        if (cc->cycles > 0) {
-               ah->survey.channel_time += cc->cycles / div;
-               ah->survey.channel_time_busy += cc->rx_busy / div;
-               ah->survey.channel_time_rx += cc->rx_frame / div;
-               ah->survey.channel_time_tx += cc->tx_frame / div;
+               ah->survey.time += cc->cycles / div;
+               ah->survey.time_busy += cc->rx_busy / div;
+               ah->survey.time_rx += cc->rx_frame / div;
+               ah->survey.time_tx += cc->tx_frame / div;
        }
        memset(cc, 0, sizeof(*cc));
        spin_unlock_bh(&common->cc_lock);
@@ -686,10 +686,10 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
        survey->noise = ah->ah_noise_floor;
        survey->filled = SURVEY_INFO_NOISE_DBM |
                        SURVEY_INFO_IN_USE |
-                       SURVEY_INFO_CHANNEL_TIME |
-                       SURVEY_INFO_CHANNEL_TIME_BUSY |
-                       SURVEY_INFO_CHANNEL_TIME_RX |
-                       SURVEY_INFO_CHANNEL_TIME_TX;
+                       SURVEY_INFO_TIME |
+                       SURVEY_INFO_TIME_BUSY |
+                       SURVEY_INFO_TIME_RX |
+                       SURVEY_INFO_TIME_TX;
 
        return 0;
 }
index 7a53378..44dd6ef 100644 (file)
@@ -1799,20 +1799,20 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
 
        if (vif->target_stats.rx_byte) {
                sinfo->rx_bytes = vif->target_stats.rx_byte;
-               sinfo->filled |= STATION_INFO_RX_BYTES64;
+               sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
                sinfo->rx_packets = vif->target_stats.rx_pkt;
-               sinfo->filled |= STATION_INFO_RX_PACKETS;
+               sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
        }
 
        if (vif->target_stats.tx_byte) {
                sinfo->tx_bytes = vif->target_stats.tx_byte;
-               sinfo->filled |= STATION_INFO_TX_BYTES64;
+               sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64);
                sinfo->tx_packets = vif->target_stats.tx_pkt;
-               sinfo->filled |= STATION_INFO_TX_PACKETS;
+               sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
        }
 
        sinfo->signal = vif->target_stats.cs_rssi;
-       sinfo->filled |= STATION_INFO_SIGNAL;
+       sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
 
        rate = vif->target_stats.tx_ucast_rate;
 
@@ -1844,12 +1844,12 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
                return 0;
        }
 
-       sinfo->filled |= STATION_INFO_TX_BITRATE;
+       sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
 
        if (test_bit(CONNECTED, &vif->flags) &&
            test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
            vif->nw_type == INFRA_NETWORK) {
-               sinfo->filled |= STATION_INFO_BSS_PARAM;
+               sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
                sinfo->bss_param.flags = 0;
                sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
                sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
index 933aef0..b42ba46 100644 (file)
@@ -488,7 +488,6 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
 
        sinfo.assoc_req_ies = ies;
        sinfo.assoc_req_ies_len = ies_len;
-       sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
 
        cfg80211_new_sta(vif->ndev, mac_addr, &sinfo, GFP_KERNEL);
 
index b829263..90631d7 100644 (file)
@@ -516,14 +516,14 @@ int ath_update_survey_stats(struct ath_softc *sc)
                ath_hw_cycle_counters_update(common);
 
        if (cc->cycles > 0) {
-               survey->filled |= SURVEY_INFO_CHANNEL_TIME |
-                       SURVEY_INFO_CHANNEL_TIME_BUSY |
-                       SURVEY_INFO_CHANNEL_TIME_RX |
-                       SURVEY_INFO_CHANNEL_TIME_TX;
-               survey->channel_time += cc->cycles / div;
-               survey->channel_time_busy += cc->rx_busy / div;
-               survey->channel_time_rx += cc->rx_frame / div;
-               survey->channel_time_tx += cc->tx_frame / div;
+               survey->filled |= SURVEY_INFO_TIME |
+                       SURVEY_INFO_TIME_BUSY |
+                       SURVEY_INFO_TIME_RX |
+                       SURVEY_INFO_TIME_TX;
+               survey->time += cc->cycles / div;
+               survey->time_busy += cc->rx_busy / div;
+               survey->time_rx += cc->rx_frame / div;
+               survey->time_tx += cc->tx_frame / div;
        }
 
        if (cc->cycles < div)
index 52d63de..cf60cc4 100644 (file)
@@ -2259,7 +2259,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
        struct ath_txq *txq = txctl->txq;
        struct ath_atx_tid *tid = NULL;
        struct ath_buf *bf;
-       bool queue, skip_uapsd = false;
+       bool queue, skip_uapsd = false, ps_resp;
        int q, ret;
 
        if (vif)
@@ -2268,6 +2268,8 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
        if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
                txctl->force_channel = true;
 
+       ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
+
        ret = ath_tx_prepare(hw, skb, txctl);
        if (ret)
            return ret;
@@ -2310,7 +2312,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
        if (txctl->an && queue)
                tid = ath_get_skb_tid(sc, txctl->an, skb);
 
-       if (!skip_uapsd && (info->flags & IEEE80211_TX_CTL_PS_RESPONSE)) {
+       if (!skip_uapsd && ps_resp) {
                ath_txq_unlock(sc, txq);
                txq = sc->tx.uapsdq;
                ath_txq_lock(sc, txq);
index 39a6387..f2b4f53 100644 (file)
@@ -188,12 +188,12 @@ int carl9170_collect_tally(struct ar9170 *ar)
 
                if (ar->channel) {
                        info = &ar->survey[ar->channel->hw_value];
-                       info->channel_time = ar->tally.active;
-                       info->channel_time_busy = ar->tally.cca;
-                       info->channel_time_tx = ar->tally.tx_time;
-                       do_div(info->channel_time, 1000);
-                       do_div(info->channel_time_busy, 1000);
-                       do_div(info->channel_time_tx, 1000);
+                       info->time = ar->tally.active;
+                       info->time_busy = ar->tally.cca;
+                       info->time_tx = ar->tally.tx_time;
+                       do_div(info->time, 1000);
+                       do_div(info->time_busy, 1000);
+                       do_div(info->time_tx, 1000);
                }
        }
        return 0;
index ef5b6dc..f1455a0 100644 (file)
@@ -1690,9 +1690,9 @@ found:
                survey->filled |= SURVEY_INFO_IN_USE;
 
        if (ar->fw.hw_counters) {
-               survey->filled |= SURVEY_INFO_CHANNEL_TIME |
-                                 SURVEY_INFO_CHANNEL_TIME_BUSY |
-                                 SURVEY_INFO_CHANNEL_TIME_TX;
+               survey->filled |= SURVEY_INFO_TIME |
+                                 SURVEY_INFO_TIME_BUSY |
+                                 SURVEY_INFO_TIME_TX;
        }
 
        return 0;
index 38332a6..e72a95d 100644 (file)
@@ -142,14 +142,14 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
 
        sinfo->generation = wil->sinfo_gen;
 
-       sinfo->filled = STATION_INFO_RX_BYTES |
-                       STATION_INFO_TX_BYTES |
-                       STATION_INFO_RX_PACKETS |
-                       STATION_INFO_TX_PACKETS |
-                       STATION_INFO_RX_BITRATE |
-                       STATION_INFO_TX_BITRATE |
-                       STATION_INFO_RX_DROP_MISC |
-                       STATION_INFO_TX_FAILED;
+       sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) |
+                       BIT(NL80211_STA_INFO_TX_BYTES) |
+                       BIT(NL80211_STA_INFO_RX_PACKETS) |
+                       BIT(NL80211_STA_INFO_TX_PACKETS) |
+                       BIT(NL80211_STA_INFO_RX_BITRATE) |
+                       BIT(NL80211_STA_INFO_TX_BITRATE) |
+                       BIT(NL80211_STA_INFO_RX_DROP_MISC) |
+                       BIT(NL80211_STA_INFO_TX_FAILED);
 
        sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
        sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
@@ -163,7 +163,7 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
        sinfo->tx_failed = stats->tx_errors;
 
        if (test_bit(wil_status_fwconnected, &wil->status)) {
-               sinfo->filled |= STATION_INFO_SIGNAL;
+               sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
                sinfo->signal = reply.evt.sqi;
        }
 
index 63476c8..8997549 100644 (file)
@@ -457,7 +457,6 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
                if (assoc_req_ie) {
                        sinfo.assoc_req_ies = assoc_req_ie;
                        sinfo.assoc_req_ies_len = assoc_req_ielen;
-                       sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
                }
 
                cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
index 3aecc5f..4a88b23 100644 (file)
@@ -2333,10 +2333,10 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
                        brcmf_err("GET STA INFO failed, %d\n", err);
                        goto done;
                }
-               sinfo->filled = STATION_INFO_INACTIVE_TIME;
+               sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
                sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
                if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
-                       sinfo->filled |= STATION_INFO_CONNECTED_TIME;
+                       sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
                        sinfo->connected_time = le32_to_cpu(sta_info_le.in);
                }
                brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
@@ -2354,7 +2354,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
                        brcmf_err("Could not get rate (%d)\n", err);
                        goto done;
                } else {
-                       sinfo->filled |= STATION_INFO_TX_BITRATE;
+                       sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
                        sinfo->txrate.legacy = rate * 5;
                        brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
                }
@@ -2369,7 +2369,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
                                goto done;
                        } else {
                                rssi = le32_to_cpu(scb_val.val);
-                               sinfo->filled |= STATION_INFO_SIGNAL;
+                               sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
                                sinfo->signal = rssi;
                                brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
                        }
@@ -2396,7 +2396,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
                                brcmf_dbg(CONN, "DTIM peroid %d\n",
                                          dtim_period);
                        }
-                       sinfo->filled |= STATION_INFO_BSS_PARAM;
+                       sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
                }
        } else
                err = -EPERM;
@@ -4778,7 +4778,6 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
        if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
            (reason == BRCMF_E_STATUS_SUCCESS)) {
                memset(&sinfo, 0, sizeof(sinfo));
-               sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
                if (!data) {
                        brcmf_err("No IEs present in ASSOC/REASSOC_IND");
                        return -EINVAL;
index 3e78cc3..0da6e42 100644 (file)
@@ -282,7 +282,6 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
                    IEEE80211_HW_SUPPORTS_PS |
                    IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
                    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
-                   IEEE80211_HW_SUPPORTS_UAPSD |
                    IEEE80211_HW_CONNECTION_MONITOR |
                    IEEE80211_HW_AMPDU_AGGREGATION |
                    IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
index 5b84664..4a47c7f 100644 (file)
@@ -213,6 +213,7 @@ int cw1200_add_interface(struct ieee80211_hw *dev,
        /* __le32 auto_calibration_mode = __cpu_to_le32(1); */
 
        vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
+                            IEEE80211_VIF_SUPPORTS_UAPSD |
                             IEEE80211_VIF_SUPPORTS_CQM_RSSI;
 
        mutex_lock(&priv->conf_mutex);
@@ -708,7 +709,8 @@ int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
                if (sta)
                        peer_addr = sta->addr;
 
-               key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
+               key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE |
+                             IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
 
                switch (key->cipher) {
                case WLAN_CIPHER_SUITE_WEP40:
index e880f9d..17358a8 100644 (file)
@@ -326,6 +326,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC |
                IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED;
        hw->rate_control_algorithm = "iwl-mvm-rs";
+       hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
+       hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
 
        /*
         * Enable 11w if advertised by firmware and software crypto
@@ -336,13 +338,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
            !iwlwifi_mod_params.sw_crypto)
                hw->flags |= IEEE80211_HW_MFP_CAPABLE;
 
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT &&
-           !iwlwifi_mod_params.uapsd_disable) {
-               hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
-               hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
-               hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
-       }
-
        if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN ||
            mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
                hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
@@ -1158,6 +1153,10 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                mvm->bf_allowed_vif = mvmvif;
                vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
                                     IEEE80211_VIF_SUPPORTS_CQM_RSSI;
+               if (mvm->fw->ucode_capa.flags &
+                                       IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT &&
+                   !iwlwifi_mod_params.uapsd_disable)
+                       vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
        }
 
        /*
index 34f09ef..a92985a 100644 (file)
@@ -1616,10 +1616,10 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
 
        lbs_deb_enter(LBS_DEB_CFG80211);
 
-       sinfo->filled |= STATION_INFO_TX_BYTES |
-                        STATION_INFO_TX_PACKETS |
-                        STATION_INFO_RX_BYTES |
-                        STATION_INFO_RX_PACKETS;
+       sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) |
+                        BIT(NL80211_STA_INFO_TX_PACKETS) |
+                        BIT(NL80211_STA_INFO_RX_BYTES) |
+                        BIT(NL80211_STA_INFO_RX_PACKETS);
        sinfo->tx_bytes = priv->dev->stats.tx_bytes;
        sinfo->tx_packets = priv->dev->stats.tx_packets;
        sinfo->rx_bytes = priv->dev->stats.rx_bytes;
@@ -1629,14 +1629,14 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
        ret = lbs_get_rssi(priv, &signal, &noise);
        if (ret == 0) {
                sinfo->signal = signal;
-               sinfo->filled |= STATION_INFO_SIGNAL;
+               sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
        }
 
        /* Convert priv->cur_rate from hw_value to NL80211 value */
        for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
                if (priv->cur_rate == lbs_rates[i].hw_value) {
                        sinfo->txrate.legacy = lbs_rates[i].bitrate;
-                       sinfo->filled |= STATION_INFO_TX_BITRATE;
+                       sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
                        break;
                }
        }
index ef58a88..494e733 100644 (file)
@@ -625,22 +625,22 @@ static int hwsim_fops_ps_write(void *dat, u64 val)
        old_ps = data->ps;
        data->ps = val;
 
+       local_bh_disable();
        if (val == PS_MANUAL_POLL) {
-               ieee80211_iterate_active_interfaces(data->hw,
-                                                   IEEE80211_IFACE_ITER_NORMAL,
-                                                   hwsim_send_ps_poll, data);
+               ieee80211_iterate_active_interfaces_atomic(
+                       data->hw, IEEE80211_IFACE_ITER_NORMAL,
+                       hwsim_send_ps_poll, data);
                data->ps_poll_pending = true;
        } else if (old_ps == PS_DISABLED && val != PS_DISABLED) {
-               ieee80211_iterate_active_interfaces(data->hw,
-                                                   IEEE80211_IFACE_ITER_NORMAL,
-                                                   hwsim_send_nullfunc_ps,
-                                                   data);
+               ieee80211_iterate_active_interfaces_atomic(
+                       data->hw, IEEE80211_IFACE_ITER_NORMAL,
+                       hwsim_send_nullfunc_ps, data);
        } else if (old_ps != PS_DISABLED && val == PS_DISABLED) {
-               ieee80211_iterate_active_interfaces(data->hw,
-                                                   IEEE80211_IFACE_ITER_NORMAL,
-                                                   hwsim_send_nullfunc_no_ps,
-                                                   data);
+               ieee80211_iterate_active_interfaces_atomic(
+                       data->hw, IEEE80211_IFACE_ITER_NORMAL,
+                       hwsim_send_nullfunc_no_ps, data);
        }
+       local_bh_enable();
 
        return 0;
 }
@@ -2149,14 +2149,14 @@ static int append_radio_msg(struct sk_buff *skb, int id,
        if (param->regd) {
                int i;
 
-               for (i = 0; hwsim_world_regdom_custom[i] != param->regd &&
-                    i < ARRAY_SIZE(hwsim_world_regdom_custom); i++)
-                       ;
+               for (i = 0; i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) {
+                       if (hwsim_world_regdom_custom[i] != param->regd)
+                               continue;
 
-               if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) {
                        ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i);
                        if (ret < 0)
                                return ret;
+                       break;
                }
        }
 
index 4a66a65..71312ff 100644 (file)
@@ -910,10 +910,10 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
 {
        u32 rate;
 
-       sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
-                       STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS |
-                       STATION_INFO_TX_BITRATE |
-                       STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
+       sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) | BIT(NL80211_STA_INFO_TX_BYTES) |
+                       BIT(NL80211_STA_INFO_RX_PACKETS) | BIT(NL80211_STA_INFO_TX_PACKETS) |
+                       BIT(NL80211_STA_INFO_TX_BITRATE) |
+                       BIT(NL80211_STA_INFO_SIGNAL) | BIT(NL80211_STA_INFO_SIGNAL_AVG);
 
        /* Get signal information from the firmware */
        if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
@@ -944,7 +944,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
        sinfo->txrate.legacy = rate * 5;
 
        if (priv->bss_mode == NL80211_IFTYPE_STATION) {
-               sinfo->filled |= STATION_INFO_BSS_PARAM;
+               sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
                sinfo->bss_param.flags = 0;
                if (priv->curr_bss_params.bss_descriptor.cap_info_bitmap &
                                                WLAN_CAPABILITY_SHORT_PREAMBLE)
@@ -1037,10 +1037,11 @@ mwifiex_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
        survey->channel = ieee80211_get_channel(wiphy,
            ieee80211_channel_to_frequency(pchan_stats[idx].chan_num, band));
        survey->filled = SURVEY_INFO_NOISE_DBM |
-               SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY;
+                        SURVEY_INFO_TIME |
+                        SURVEY_INFO_TIME_BUSY;
        survey->noise = pchan_stats[idx].noise;
-       survey->channel_time = pchan_stats[idx].cca_scan_dur;
-       survey->channel_time_busy = pchan_stats[idx].cca_busy_dur;
+       survey->time = pchan_stats[idx].cca_scan_dur;
+       survey->time_busy = pchan_stats[idx].cca_busy_dur;
 
        return 0;
 }
index c54a537..3b3a970 100644 (file)
@@ -68,7 +68,6 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
                                len = ETH_ALEN;
 
                        if (len != -1) {
-                               sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
                                sinfo.assoc_req_ies = &event->data[len];
                                len = (u8 *)sinfo.assoc_req_ies -
                                      (u8 *)&event->frame_control;
index b8d1e04..f9b1218 100644 (file)
@@ -3098,14 +3098,14 @@ static void mwl8k_update_survey(struct mwl8k_priv *priv,
 
        cca_cnt = ioread32(priv->regs + NOK_CCA_CNT_REG);
        cca_cnt /= 1000; /* uSecs to mSecs */
-       survey->channel_time_busy = (u64) cca_cnt;
+       survey->time_busy = (u64) cca_cnt;
 
        rx_rdy = ioread32(priv->regs + BBU_RXRDY_CNT_REG);
        rx_rdy /= 1000; /* uSecs to mSecs */
-       survey->channel_time_rx = (u64) rx_rdy;
+       survey->time_rx = (u64) rx_rdy;
 
        priv->channel_time = jiffies - priv->channel_time;
-       survey->channel_time = jiffies_to_msecs(priv->channel_time);
+       survey->time = jiffies_to_msecs(priv->channel_time);
 
        survey->channel = channel;
 
@@ -3115,9 +3115,9 @@ static void mwl8k_update_survey(struct mwl8k_priv *priv,
        survey->noise = nf * -1;
 
        survey->filled = SURVEY_INFO_NOISE_DBM |
-                        SURVEY_INFO_CHANNEL_TIME |
-                        SURVEY_INFO_CHANNEL_TIME_BUSY |
-                        SURVEY_INFO_CHANNEL_TIME_RX;
+                        SURVEY_INFO_TIME |
+                        SURVEY_INFO_TIME_BUSY |
+                        SURVEY_INFO_TIME_RX;
 }
 
 /*
index 0fe67d2..2fe713e 100644 (file)
@@ -196,9 +196,9 @@ static int p54_generate_band(struct ieee80211_hw *dev,
                dest->max_power = chan->max_power;
                priv->survey[*chan_num].channel = &tmp->channels[j];
                priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
-                       SURVEY_INFO_CHANNEL_TIME |
-                       SURVEY_INFO_CHANNEL_TIME_BUSY |
-                       SURVEY_INFO_CHANNEL_TIME_TX;
+                       SURVEY_INFO_TIME |
+                       SURVEY_INFO_TIME_BUSY |
+                       SURVEY_INFO_TIME_TX;
                dest->hw_value = (*chan_num);
                j++;
                (*chan_num)++;
index 97aeff0..b9250d7 100644 (file)
@@ -305,9 +305,9 @@ static void p54_reset_stats(struct p54_common *priv)
                struct survey_info *info = &priv->survey[chan->hw_value];
 
                /* only reset channel statistics, don't touch .filled, etc. */
-               info->channel_time = 0;
-               info->channel_time_busy = 0;
-               info->channel_time_tx = 0;
+               info->time = 0;
+               info->time_busy = 0;
+               info->time_tx = 0;
        }
 
        priv->update_stats = true;
@@ -575,6 +575,8 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
                        key->hw_key_idx = 0xff;
                        goto out_unlock;
                }
+
+               key->flags |= IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
        } else {
                slot = key->hw_key_idx;
 
@@ -634,7 +636,7 @@ static int p54_get_survey(struct ieee80211_hw *dev, int idx,
 
                if (in_use) {
                        /* test if the reported statistics are valid. */
-                       if  (survey->channel_time != 0) {
+                       if  (survey->time != 0) {
                                survey->filled |= SURVEY_INFO_IN_USE;
                        } else {
                                /*
index 153c615..24e5ff9 100644 (file)
@@ -587,13 +587,13 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
        if (chan) {
                struct survey_info *survey = &priv->survey[chan->hw_value];
                survey->noise = clamp(priv->noise, -128, 127);
-               survey->channel_time = priv->survey_raw.active;
-               survey->channel_time_tx = priv->survey_raw.tx;
-               survey->channel_time_busy = priv->survey_raw.tx +
+               survey->time = priv->survey_raw.active;
+               survey->time_tx = priv->survey_raw.tx;
+               survey->time_busy = priv->survey_raw.tx +
                        priv->survey_raw.cca;
-               do_div(survey->channel_time, 1024);
-               do_div(survey->channel_time_tx, 1024);
-               do_div(survey->channel_time_busy, 1024);
+               do_div(survey->time, 1024);
+               do_div(survey->time_tx, 1024);
+               do_div(survey->time_busy, 1024);
        }
 
        tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
index 1a4facd..60d44ce 100644 (file)
@@ -2478,7 +2478,7 @@ static void rndis_fill_station_info(struct usbnet *usbdev,
        ret = rndis_query_oid(usbdev, RNDIS_OID_GEN_LINK_SPEED, &linkspeed, &len);
        if (ret == 0) {
                sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000;
-               sinfo->filled |= STATION_INFO_TX_BITRATE;
+               sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
        }
 
        len = sizeof(rssi);
@@ -2486,7 +2486,7 @@ static void rndis_fill_station_info(struct usbnet *usbdev,
                              &rssi, &len);
        if (ret == 0) {
                sinfo->signal = level_to_qual(le32_to_cpu(rssi));
-               sinfo->filled |= STATION_INFO_SIGNAL;
+               sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
        }
 }
 
index 81ee481..be2d54f 100644 (file)
@@ -8020,13 +8020,13 @@ int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
        rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &busy_ext);
 
        if (idle || busy) {
-               survey->filled = SURVEY_INFO_CHANNEL_TIME |
-                                SURVEY_INFO_CHANNEL_TIME_BUSY |
-                                SURVEY_INFO_CHANNEL_TIME_EXT_BUSY;
+               survey->filled = SURVEY_INFO_TIME |
+                                SURVEY_INFO_TIME_BUSY |
+                                SURVEY_INFO_TIME_EXT_BUSY;
 
-               survey->channel_time = (idle + busy) / 1000;
-               survey->channel_time_busy = busy / 1000;
-               survey->channel_time_ext_busy = busy_ext / 1000;
+               survey->time = (idle + busy) / 1000;
+               survey->time_busy = busy / 1000;
+               survey->time_ext_busy = busy_ext / 1000;
        }
 
        if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
index 0b30a7b..d4ba009 100644 (file)
@@ -500,6 +500,7 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
        int ret = 0;
 
        vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
+                            IEEE80211_VIF_SUPPORTS_UAPSD |
                             IEEE80211_VIF_SUPPORTS_CQM_RSSI;
 
        wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
@@ -1480,9 +1481,7 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
        /* unit us */
        /* FIXME: find a proper value */
 
-       wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
-               IEEE80211_HW_SUPPORTS_PS |
-               IEEE80211_HW_SUPPORTS_UAPSD;
+       wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS;
 
        wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
                                         BIT(NL80211_IFTYPE_ADHOC);
index 6ad3fce..a2133b1 100644 (file)
@@ -2508,6 +2508,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
        }
 
        vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
+                            IEEE80211_VIF_SUPPORTS_UAPSD |
                             IEEE80211_VIF_SUPPORTS_CQM_RSSI;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
@@ -5375,14 +5376,15 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
        wlcore_hw_sta_rc_update(wl, wlvif, sta, changed);
 }
 
-static int wlcore_op_get_rssi(struct ieee80211_hw *hw,
-                              struct ieee80211_vif *vif,
-                              struct ieee80211_sta *sta,
-                              s8 *rssi_dbm)
+static void wlcore_op_sta_statistics(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif,
+                                    struct ieee80211_sta *sta,
+                                    struct station_info *sinfo)
 {
        struct wl1271 *wl = hw->priv;
        struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
-       int ret = 0;
+       s8 rssi_dbm;
+       int ret;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi");
 
@@ -5395,17 +5397,18 @@ static int wlcore_op_get_rssi(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out_sleep;
 
-       ret = wlcore_acx_average_rssi(wl, wlvif, rssi_dbm);
+       ret = wlcore_acx_average_rssi(wl, wlvif, &rssi_dbm);
        if (ret < 0)
                goto out_sleep;
 
+       sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
+       sinfo->signal = rssi_dbm;
+
 out_sleep:
        wl1271_ps_elp_sleep(wl);
 
 out:
        mutex_unlock(&wl->mutex);
-
-       return ret;
 }
 
 static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
@@ -5605,7 +5608,7 @@ static const struct ieee80211_ops wl1271_ops = {
        .assign_vif_chanctx = wlcore_op_assign_vif_chanctx,
        .unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx,
        .sta_rc_update = wlcore_op_sta_rc_update,
-       .get_rssi = wlcore_op_get_rssi,
+       .sta_statistics = wlcore_op_sta_statistics,
        CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
 };
 
@@ -5776,7 +5779,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
        wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
                IEEE80211_HW_SUPPORTS_PS |
                IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
-               IEEE80211_HW_SUPPORTS_UAPSD |
                IEEE80211_HW_HAS_RATE_CONTROL |
                IEEE80211_HW_CONNECTION_MONITOR |
                IEEE80211_HW_REPORTS_TX_ACK_STATUS |
index 82a8c06..c5800ae 100644 (file)
@@ -1091,17 +1091,17 @@ static int cfg80211_rtw_get_station(struct wiphy *wiphy,
                        goto exit;
                }
 
-               sinfo->filled |= STATION_INFO_SIGNAL;
+               sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
                sinfo->signal = translate_percentage_to_dbm(padapter->recvpriv.
                                                            signal_strength);
 
-               sinfo->filled |= STATION_INFO_TX_BITRATE;
+               sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
                sinfo->txrate.legacy = rtw_get_cur_max_rate(padapter);
 
-               sinfo->filled |= STATION_INFO_RX_PACKETS;
+               sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
                sinfo->rx_packets = sta_rx_data_pkts(psta);
 
-               sinfo->filled |= STATION_INFO_TX_PACKETS;
+               sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
                sinfo->tx_packets = psta->sta_stats.tx_pkts;
        }
 
@@ -2363,7 +2363,7 @@ void rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter,
                        ie_offset = offsetof(struct ieee80211_mgmt,
                                             u.reassoc_req.variable);
 
-               sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+               sinfo.filled = 0;
                sinfo.assoc_req_ies = pmgmt_frame + ie_offset;
                sinfo.assoc_req_ies_len = frame_len - ie_offset;
                cfg80211_new_sta(ndev, hdr->addr2, &sinfo, GFP_ATOMIC);
index 8942dcb..7c87aec 100644 (file)
@@ -325,9 +325,9 @@ static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
 
        if (result == 0) {
                sinfo->txrate.legacy = quality.txrate.data;
-               sinfo->filled |= STATION_INFO_TX_BITRATE;
+               sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
                sinfo->signal = quality.level.data;
-               sinfo->filled |= STATION_INFO_SIGNAL;
+               sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
        }
 
        return result;
index 4ebb816..38abc07 100644 (file)
@@ -520,37 +520,41 @@ ieee80211_chandef_max_power(struct cfg80211_chan_def *chandef)
  *
  * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in
  * @SURVEY_INFO_IN_USE: channel is currently being used
- * @SURVEY_INFO_CHANNEL_TIME: channel active time (in ms) was filled in
- * @SURVEY_INFO_CHANNEL_TIME_BUSY: channel busy time was filled in
- * @SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: extension channel busy time was filled in
- * @SURVEY_INFO_CHANNEL_TIME_RX: channel receive time was filled in
- * @SURVEY_INFO_CHANNEL_TIME_TX: channel transmit time was filled in
+ * @SURVEY_INFO_TIME: active time (in ms) was filled in
+ * @SURVEY_INFO_TIME_BUSY: busy time was filled in
+ * @SURVEY_INFO_TIME_EXT_BUSY: extension channel busy time was filled in
+ * @SURVEY_INFO_TIME_RX: receive time was filled in
+ * @SURVEY_INFO_TIME_TX: transmit time was filled in
+ * @SURVEY_INFO_TIME_SCAN: scan time was filled in
  *
  * Used by the driver to indicate which info in &struct survey_info
  * it has filled in during the get_survey().
  */
 enum survey_info_flags {
-       SURVEY_INFO_NOISE_DBM = 1<<0,
-       SURVEY_INFO_IN_USE = 1<<1,
-       SURVEY_INFO_CHANNEL_TIME = 1<<2,
-       SURVEY_INFO_CHANNEL_TIME_BUSY = 1<<3,
-       SURVEY_INFO_CHANNEL_TIME_EXT_BUSY = 1<<4,
-       SURVEY_INFO_CHANNEL_TIME_RX = 1<<5,
-       SURVEY_INFO_CHANNEL_TIME_TX = 1<<6,
+       SURVEY_INFO_NOISE_DBM           = BIT(0),
+       SURVEY_INFO_IN_USE              = BIT(1),
+       SURVEY_INFO_TIME                = BIT(2),
+       SURVEY_INFO_TIME_BUSY           = BIT(3),
+       SURVEY_INFO_TIME_EXT_BUSY       = BIT(4),
+       SURVEY_INFO_TIME_RX             = BIT(5),
+       SURVEY_INFO_TIME_TX             = BIT(6),
+       SURVEY_INFO_TIME_SCAN           = BIT(7),
 };
 
 /**
  * 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
  * @noise: channel noise in dBm. This and all following fields are
  *     optional
- * @channel_time: amount of time in ms the radio spent on the channel
- * @channel_time_busy: amount of time the primary channel was sensed busy
- * @channel_time_ext_busy: amount of time the extension channel was sensed busy
- * @channel_time_rx: amount of time the radio spent receiving data
- * @channel_time_tx: amount of time the radio spent transmitting data
+ * @time: amount of time in ms the radio was turn on (on the channel)
+ * @time_busy: amount of time the primary channel was sensed busy
+ * @time_ext_busy: amount of time the extension channel was sensed busy
+ * @time_rx: amount of time the radio spent receiving data
+ * @time_tx: amount of time the radio spent transmitting data
+ * @time_scan: amount of time the radio spent for scanning
  *
  * Used by dump_survey() to report back per-channel survey information.
  *
@@ -559,11 +563,12 @@ enum survey_info_flags {
  */
 struct survey_info {
        struct ieee80211_channel *channel;
-       u64 channel_time;
-       u64 channel_time_busy;
-       u64 channel_time_ext_busy;
-       u64 channel_time_rx;
-       u64 channel_time_tx;
+       u64 time;
+       u64 time_busy;
+       u64 time_ext_busy;
+       u64 time_rx;
+       u64 time_tx;
+       u64 time_scan;
        u32 filled;
        s8 noise;
 };
@@ -860,75 +865,6 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
                                  struct station_parameters *params,
                                  enum cfg80211_station_type statype);
 
-/**
- * enum station_info_flags - station information flags
- *
- * Used by the driver to indicate which info in &struct station_info
- * it has filled in during get_station() or dump_station().
- *
- * @STATION_INFO_INACTIVE_TIME: @inactive_time filled
- * @STATION_INFO_RX_BYTES: @rx_bytes filled
- * @STATION_INFO_TX_BYTES: @tx_bytes filled
- * @STATION_INFO_RX_BYTES64: @rx_bytes filled with 64-bit value
- * @STATION_INFO_TX_BYTES64: @tx_bytes filled with 64-bit value
- * @STATION_INFO_LLID: @llid filled
- * @STATION_INFO_PLID: @plid filled
- * @STATION_INFO_PLINK_STATE: @plink_state filled
- * @STATION_INFO_SIGNAL: @signal filled
- * @STATION_INFO_TX_BITRATE: @txrate fields are filled
- *     (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
- * @STATION_INFO_RX_PACKETS: @rx_packets filled with 32-bit value
- * @STATION_INFO_TX_PACKETS: @tx_packets filled with 32-bit value
- * @STATION_INFO_TX_RETRIES: @tx_retries filled
- * @STATION_INFO_TX_FAILED: @tx_failed filled
- * @STATION_INFO_RX_DROP_MISC: @rx_dropped_misc filled
- * @STATION_INFO_SIGNAL_AVG: @signal_avg filled
- * @STATION_INFO_RX_BITRATE: @rxrate fields are filled
- * @STATION_INFO_BSS_PARAM: @bss_param filled
- * @STATION_INFO_CONNECTED_TIME: @connected_time filled
- * @STATION_INFO_ASSOC_REQ_IES: @assoc_req_ies filled
- * @STATION_INFO_STA_FLAGS: @sta_flags filled
- * @STATION_INFO_BEACON_LOSS_COUNT: @beacon_loss_count filled
- * @STATION_INFO_T_OFFSET: @t_offset filled
- * @STATION_INFO_LOCAL_PM: @local_pm filled
- * @STATION_INFO_PEER_PM: @peer_pm filled
- * @STATION_INFO_NONPEER_PM: @nonpeer_pm filled
- * @STATION_INFO_CHAIN_SIGNAL: @chain_signal filled
- * @STATION_INFO_CHAIN_SIGNAL_AVG: @chain_signal_avg filled
- * @STATION_INFO_EXPECTED_THROUGHPUT: @expected_throughput filled
- */
-enum station_info_flags {
-       STATION_INFO_INACTIVE_TIME              = BIT(0),
-       STATION_INFO_RX_BYTES                   = BIT(1),
-       STATION_INFO_TX_BYTES                   = BIT(2),
-       STATION_INFO_LLID                       = BIT(3),
-       STATION_INFO_PLID                       = BIT(4),
-       STATION_INFO_PLINK_STATE                = BIT(5),
-       STATION_INFO_SIGNAL                     = BIT(6),
-       STATION_INFO_TX_BITRATE                 = BIT(7),
-       STATION_INFO_RX_PACKETS                 = BIT(8),
-       STATION_INFO_TX_PACKETS                 = BIT(9),
-       STATION_INFO_TX_RETRIES                 = BIT(10),
-       STATION_INFO_TX_FAILED                  = BIT(11),
-       STATION_INFO_RX_DROP_MISC               = BIT(12),
-       STATION_INFO_SIGNAL_AVG                 = BIT(13),
-       STATION_INFO_RX_BITRATE                 = BIT(14),
-       STATION_INFO_BSS_PARAM                  = BIT(15),
-       STATION_INFO_CONNECTED_TIME             = BIT(16),
-       STATION_INFO_ASSOC_REQ_IES              = BIT(17),
-       STATION_INFO_STA_FLAGS                  = BIT(18),
-       STATION_INFO_BEACON_LOSS_COUNT          = BIT(19),
-       STATION_INFO_T_OFFSET                   = BIT(20),
-       STATION_INFO_LOCAL_PM                   = BIT(21),
-       STATION_INFO_PEER_PM                    = BIT(22),
-       STATION_INFO_NONPEER_PM                 = BIT(23),
-       STATION_INFO_RX_BYTES64                 = BIT(24),
-       STATION_INFO_TX_BYTES64                 = BIT(25),
-       STATION_INFO_CHAIN_SIGNAL               = BIT(26),
-       STATION_INFO_CHAIN_SIGNAL_AVG           = BIT(27),
-       STATION_INFO_EXPECTED_THROUGHPUT        = BIT(28),
-};
-
 /**
  * enum station_info_rate_flags - bitrate info flags
  *
@@ -1003,6 +939,24 @@ struct sta_bss_parameters {
        u16 beacon_interval;
 };
 
+/**
+ * struct cfg80211_tid_stats - per-TID statistics
+ * @filled: bitmap of flags using the bits of &enum nl80211_tid_stats to
+ *     indicate the relevant values in this struct are filled
+ * @rx_msdu: number of received MSDUs
+ * @tx_msdu: number of (attempted) transmitted MSDUs
+ * @tx_msdu_retries: number of retries (not counting the first) for
+ *     transmitted MSDUs
+ * @tx_msdu_failed: number of failed transmitted MSDUs
+ */
+struct cfg80211_tid_stats {
+       u32 filled;
+       u64 rx_msdu;
+       u64 tx_msdu;
+       u64 tx_msdu_retries;
+       u64 tx_msdu_failed;
+};
+
 #define IEEE80211_MAX_CHAINS   4
 
 /**
@@ -1010,11 +964,12 @@ struct sta_bss_parameters {
  *
  * Station information filled by driver for get_station() and dump_station.
  *
- * @filled: bitflag of flags from &enum station_info_flags
+ * @filled: bitflag of flags using the bits of &enum nl80211_sta_info to
+ *     indicate the relevant values in this struct for them
  * @connected_time: time(in secs) since a station is last connected
  * @inactive_time: time since last station activity (tx/rx) in milliseconds
- * @rx_bytes: bytes received from this station
- * @tx_bytes: bytes transmitted to this station
+ * @rx_bytes: bytes (size of MPDUs) received from this station
+ * @tx_bytes: bytes (size of MPDUs) transmitted to this station
  * @llid: mesh local link id
  * @plid: mesh peer link id
  * @plink_state: mesh peer link state
@@ -1027,10 +982,10 @@ struct sta_bss_parameters {
  * @chain_signal_avg: per-chain signal strength average in dBm
  * @txrate: current unicast bitrate from this station
  * @rxrate: current unicast bitrate to this station
- * @rx_packets: packets received from this station
- * @tx_packets: packets transmitted to this station
- * @tx_retries: cumulative retry counts
- * @tx_failed: number of failed transmissions (retries exceeded, no ACK)
+ * @rx_packets: packets (MSDUs & MMPDUs) received from this station
+ * @tx_packets: packets (MSDUs & MMPDUs) transmitted to this station
+ * @tx_retries: cumulative retry counts (MPDUs)
+ * @tx_failed: number of failed transmissions (MPDUs) (retries exceeded, no ACK)
  * @rx_dropped_misc:  Dropped for un-specified reason.
  * @bss_param: current BSS parameters
  * @generation: generation number for nl80211 dumps.
@@ -1050,6 +1005,11 @@ struct sta_bss_parameters {
  * @nonpeer_pm: non-peer mesh STA power save mode
  * @expected_throughput: expected throughput in kbps (including 802.11 headers)
  *     towards this station.
+ * @rx_beacon: number of beacons received from this peer
+ * @rx_beacon_signal_avg: signal strength average (in dBm) for beacons received
+ *     from this peer
+ * @pertid: per-TID statistics, see &struct cfg80211_tid_stats, using the last
+ *     (IEEE80211_NUM_TIDS) index for MSDUs not encapsulated in QoS-MPDUs.
  */
 struct station_info {
        u32 filled;
@@ -1090,10 +1050,9 @@ struct station_info {
 
        u32 expected_throughput;
 
-       /*
-        * Note: Add a new enum station_info_flags value for each new field and
-        * use it to check which fields are initialized.
-        */
+       u64 rx_beacon;
+       u8 rx_beacon_signal_avg;
+       struct cfg80211_tid_stats pertid[IEEE80211_NUM_TIDS + 1];
 };
 
 /**
@@ -1516,6 +1475,9 @@ struct cfg80211_match_set {
  * @mac_addr_mask: MAC address mask used with randomisation, bits that
  *     are 0 in the mask should be randomised, bits that are 1 should
  *     be taken from the @mac_addr
+ * @rcu_head: RCU callback used to free the struct
+ * @owner_nlportid: netlink portid of owner (if this should is a request
+ *     owned by a particular socket)
  */
 struct cfg80211_sched_scan_request {
        struct cfg80211_ssid *ssids;
@@ -1537,6 +1499,8 @@ struct cfg80211_sched_scan_request {
        struct wiphy *wiphy;
        struct net_device *dev;
        unsigned long scan_start;
+       struct rcu_head rcu_head;
+       u32 owner_nlportid;
 
        /* keep last */
        struct ieee80211_channel *channels[0];
@@ -3011,6 +2975,8 @@ struct wiphy_vendor_command {
  * @regulatory_flags: wiphy regulatory flags, see
  *     &enum ieee80211_regulatory_flags
  * @features: features advertised to nl80211, see &enum nl80211_feature_flags.
+ * @ext_features: extended features advertised to nl80211, see
+ *     &enum nl80211_ext_feature_index.
  * @bss_priv_size: each BSS struct has private data allocated with it,
  *     this variable determines its size
  * @max_scan_ssids: maximum number of SSIDs the device can scan for in
@@ -3120,6 +3086,7 @@ struct wiphy {
        u16 max_acl_mac_addrs;
 
        u32 flags, regulatory_flags, features;
+       u8 ext_features[DIV_ROUND_UP(NUM_NL80211_EXT_FEATURES, 8)];
 
        u32 ap_sme_capa;
 
@@ -3807,6 +3774,34 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
  */
 int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
 
+/**
+ * regulatory_set_wiphy_regd - set regdom info for self managed drivers
+ * @wiphy: the wireless device we want to process the regulatory domain on
+ * @rd: the regulatory domain informatoin to use for this wiphy
+ *
+ * Set the regulatory domain information for self-managed wiphys, only they
+ * may use this function. See %REGULATORY_WIPHY_SELF_MANAGED for more
+ * information.
+ *
+ * Return: 0 on success. -EINVAL, -EPERM
+ */
+int regulatory_set_wiphy_regd(struct wiphy *wiphy,
+                             struct ieee80211_regdomain *rd);
+
+/**
+ * regulatory_set_wiphy_regd_sync_rtnl - set regdom for self-managed drivers
+ * @wiphy: the wireless device we want to process the regulatory domain on
+ * @rd: the regulatory domain information to use for this wiphy
+ *
+ * This functions requires the RTNL to be held and applies the new regdomain
+ * synchronously to this wiphy. For more details see
+ * regulatory_set_wiphy_regd().
+ *
+ * Return: 0 on success. -EINVAL, -EPERM
+ */
+int regulatory_set_wiphy_regd_sync_rtnl(struct wiphy *wiphy,
+                                       struct ieee80211_regdomain *rd);
+
 /**
  * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
  * @wiphy: the wireless device we want to process the regulatory domain on
@@ -4564,6 +4559,16 @@ void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
 void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
                      struct station_info *sinfo, gfp_t gfp);
 
+/**
+ * cfg80211_del_sta_sinfo - notify userspace about deletion of a station
+ * @dev: the netdev
+ * @mac_addr: the station's address
+ * @sinfo: the station information/statistics
+ * @gfp: allocation flags
+ */
+void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
+                           struct station_info *sinfo, gfp_t gfp);
+
 /**
  * cfg80211_del_sta - notify userspace about deletion of a station
  *
@@ -4571,7 +4576,11 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
  * @mac_addr: the station's address
  * @gfp: allocation flags
  */
-void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp);
+static inline void cfg80211_del_sta(struct net_device *dev,
+                                   const u8 *mac_addr, gfp_t gfp)
+{
+       cfg80211_del_sta_sinfo(dev, mac_addr, NULL, gfp);
+}
 
 /**
  * cfg80211_conn_failed - connection request failed notification
@@ -5033,6 +5042,42 @@ void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev,
  */
 void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy);
 
+/**
+ * wiphy_ext_feature_set - set the extended feature flag
+ *
+ * @wiphy: the wiphy to modify.
+ * @ftidx: extended feature bit index.
+ *
+ * The extended features are flagged in multiple bytes (see
+ * &struct wiphy.@ext_features)
+ */
+static inline void wiphy_ext_feature_set(struct wiphy *wiphy,
+                                        enum nl80211_ext_feature_index ftidx)
+{
+       u8 *ft_byte;
+
+       ft_byte = &wiphy->ext_features[ftidx / 8];
+       *ft_byte |= BIT(ftidx % 8);
+}
+
+/**
+ * wiphy_ext_feature_isset - check the extended feature flag
+ *
+ * @wiphy: the wiphy to modify.
+ * @ftidx: extended feature bit index.
+ *
+ * The extended features are flagged in multiple bytes (see
+ * &struct wiphy.@ext_features)
+ */
+static inline bool
+wiphy_ext_feature_isset(struct wiphy *wiphy,
+                       enum nl80211_ext_feature_index ftidx)
+{
+       u8 ft_byte;
+
+       ft_byte = wiphy->ext_features[ftidx / 8];
+       return (ft_byte & BIT(ftidx % 8)) != 0;
+}
 
 /* ethtool helper */
 void cfg80211_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
index 29c7be8..123f230 100644 (file)
@@ -505,8 +505,11 @@ struct ieee80211_bss_conf {
  * @IEEE80211_TX_CTL_DONTFRAG: Don't fragment this packet even if it
  *     would be fragmented by size (this is optional, only used for
  *     monitor injection).
- * @IEEE80211_TX_CTL_PS_RESPONSE: This frame is a response to a poll
- *     frame (PS-Poll or uAPSD).
+ * @IEEE80211_TX_STAT_NOACK_TRANSMITTED: A frame that was marked with
+ *     IEEE80211_TX_CTL_NO_ACK has been successfully transmitted without
+ *     any errors (like issues specific to the driver/HW).
+ *     This flag must not be set for frames that don't request no-ack
+ *     behaviour with IEEE80211_TX_CTL_NO_ACK.
  *
  * Note: If you have to add new flags to the enumeration, then don't
  *      forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -542,7 +545,7 @@ enum mac80211_tx_info_flags {
        IEEE80211_TX_STATUS_EOSP                = BIT(28),
        IEEE80211_TX_CTL_USE_MINRATE            = BIT(29),
        IEEE80211_TX_CTL_DONTFRAG               = BIT(30),
-       IEEE80211_TX_CTL_PS_RESPONSE            = BIT(31),
+       IEEE80211_TX_STAT_NOACK_TRANSMITTED     = BIT(31),
 };
 
 #define IEEE80211_TX_CTL_STBC_SHIFT            23
@@ -552,11 +555,14 @@ enum mac80211_tx_info_flags {
  *
  * @IEEE80211_TX_CTRL_PORT_CTRL_PROTO: this frame is a port control
  *     protocol frame (e.g. EAP)
+ * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
+ *     frame (PS-Poll or uAPSD).
  *
  * These flags are used in tx_info->control.flags.
  */
 enum mac80211_tx_control_flags {
        IEEE80211_TX_CTRL_PORT_CTRL_PROTO       = BIT(0),
+       IEEE80211_TX_CTRL_PS_RESPONSE           = BIT(1),
 };
 
 /*
@@ -1181,10 +1187,15 @@ struct ieee80211_channel_switch {
  *     monitoring on this virtual interface -- i.e. it can monitor
  *     connection quality related parameters, such as the RSSI level and
  *     provide notifications if configured trigger levels are reached.
+ * @IEEE80211_VIF_SUPPORTS_UAPSD: The device can do U-APSD for this
+ *     interface. This flag should be set during interface addition,
+ *     but may be set/cleared as late as authentication to an AP. It is
+ *     only valid for managed/station mode interfaces.
  */
 enum ieee80211_vif_flags {
        IEEE80211_VIF_BEACON_FILTER             = BIT(0),
        IEEE80211_VIF_SUPPORTS_CQM_RSSI         = BIT(1),
+       IEEE80211_VIF_SUPPORTS_UAPSD            = BIT(2),
 };
 
 /**
@@ -1270,7 +1281,8 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
  *
  * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the
  *     driver to indicate that it requires IV generation for this
- *     particular key.
+ *     particular key. Setting this flag does not necessarily mean that SKBs
+ *     will have sufficient tailroom for ICV or MIC.
  * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by
  *     the driver for a TKIP key if it requires Michael MIC
  *     generation in software.
@@ -1282,7 +1294,9 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
  * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver
  *     if space should be prepared for the IV, but the IV
  *     itself should not be generated. Do not set together with
- *     @IEEE80211_KEY_FLAG_GENERATE_IV on the same key.
+ *     @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. Setting this flag does
+ *     not necessarily mean that SKBs will have sufficient tailroom for ICV or
+ *     MIC.
  * @IEEE80211_KEY_FLAG_RX_MGMT: This key will be used to decrypt received
  *     management frames. The flag can help drivers that have a hardware
  *     crypto implementation that doesn't deal with management frames
@@ -1293,6 +1307,9 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
  * @IEEE80211_KEY_FLAG_GENERATE_IV_MGMT: This flag should be set by the
  *     driver for a CCMP key to indicate that is requires IV generation
  *     only for managment frames (MFP).
+ * @IEEE80211_KEY_FLAG_RESERVE_TAILROOM: This flag should be set by the
+ *     driver for a key to indicate that sufficient tailroom must always
+ *     be reserved for ICV or MIC, even when HW encryption is enabled.
  */
 enum ieee80211_key_flags {
        IEEE80211_KEY_FLAG_GENERATE_IV_MGMT     = BIT(0),
@@ -1302,6 +1319,7 @@ enum ieee80211_key_flags {
        IEEE80211_KEY_FLAG_SW_MGMT_TX           = BIT(4),
        IEEE80211_KEY_FLAG_PUT_IV_SPACE         = BIT(5),
        IEEE80211_KEY_FLAG_RX_MGMT              = BIT(6),
+       IEEE80211_KEY_FLAG_RESERVE_TAILROOM     = BIT(7),
 };
 
 /**
@@ -1580,11 +1598,6 @@ struct ieee80211_tx_control {
  * @IEEE80211_HW_MFP_CAPABLE:
  *     Hardware supports management frame protection (MFP, IEEE 802.11w).
  *
- * @IEEE80211_HW_SUPPORTS_UAPSD:
- *     Hardware supports Unscheduled Automatic Power Save Delivery
- *     (U-APSD) in managed mode. The mode is configured with
- *     conf_tx() operation.
- *
  * @IEEE80211_HW_REPORTS_TX_ACK_STATUS:
  *     Hardware can provide ack status reports of Tx frames to
  *     the stack.
@@ -1670,8 +1683,7 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_MFP_CAPABLE                        = 1<<13,
        IEEE80211_HW_WANT_MONITOR_VIF                   = 1<<14,
        IEEE80211_HW_NO_AUTO_VIF                        = 1<<15,
-       /* free slot */
-       IEEE80211_HW_SUPPORTS_UAPSD                     = 1<<17,
+       /* free slots */
        IEEE80211_HW_REPORTS_TX_ACK_STATUS              = 1<<18,
        IEEE80211_HW_CONNECTION_MONITOR                 = 1<<19,
        IEEE80211_HW_QUEUE_CONTROL                      = 1<<20,
@@ -2023,7 +2035,7 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
  * enabled whenever user has enabled powersave.
  *
  * Driver informs U-APSD client support by enabling
- * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the
+ * %IEEE80211_VIF_SUPPORTS_UAPSD flag. The mode is configured through the
  * uapsd parameter in conf_tx() operation. Hardware needs to send the QoS
  * Nullfunc frames and stay awake until the service period has ended. To
  * utilize U-APSD, dynamic powersave is disabled for voip AC and all frames
@@ -2696,6 +2708,14 @@ enum ieee80211_reconfig_type {
  *     is only used if the configured rate control algorithm actually uses
  *     the new rate table API, and is therefore optional. Must be atomic.
  *
+ * @sta_statistics: Get statistics for this station. For example with beacon
+ *     filtering, the statistics kept by mac80211 might not be accurate, so
+ *     let the driver pre-fill the statistics. The driver can fill most of
+ *     the values (indicating which by setting the filled bitmap), but not
+ *     all of them make sense - see the source for which ones are possible.
+ *     Statistics that the driver doesn't fill will be filled by mac80211.
+ *     The callback can sleep.
+ *
  * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
  *     bursting) for a hardware TX queue.
  *     Returns a negative error code on failure.
@@ -2856,9 +2876,6 @@ enum ieee80211_reconfig_type {
  * @get_et_strings:  Ethtool API to get a set of strings to describe stats
  *     and perhaps other supported types of ethtool data-sets.
  *
- * @get_rssi: Get current signal strength in dBm, the function is optional
- *     and can sleep.
- *
  * @mgd_prepare_tx: Prepare for transmitting a management frame for association
  *     before associated. In multi-channel scenarios, a virtual interface is
  *     bound to a channel before it is associated, but as it isn't associated
@@ -3059,6 +3076,10 @@ struct ieee80211_ops {
        void (*sta_rate_tbl_update)(struct ieee80211_hw *hw,
                                    struct ieee80211_vif *vif,
                                    struct ieee80211_sta *sta);
+       void (*sta_statistics)(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_sta *sta,
+                              struct station_info *sinfo);
        int (*conf_tx)(struct ieee80211_hw *hw,
                       struct ieee80211_vif *vif, u16 ac,
                       const struct ieee80211_tx_queue_params *params);
@@ -3126,8 +3147,6 @@ struct ieee80211_ops {
        void    (*get_et_strings)(struct ieee80211_hw *hw,
                                  struct ieee80211_vif *vif,
                                  u32 sset, u8 *data);
-       int     (*get_rssi)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                           struct ieee80211_sta *sta, s8 *rssi_dbm);
 
        void    (*mgd_prepare_tx)(struct ieee80211_hw *hw,
                                  struct ieee80211_vif *vif);
index b776d72..ebc5a2e 100644 (file)
@@ -147,6 +147,24 @@ struct regulatory_request {
  *     NL80211_IFTYPE_P2P_CLIENT, NL80211_IFTYPE_P2P_GO,
  *     NL80211_IFTYPE_P2P_DEVICE. The flag will be set by default if a device
  *     includes any modes unsupported for enforcement checking.
+ * @REGULATORY_WIPHY_SELF_MANAGED: for devices that employ wiphy-specific
+ *     regdom management. These devices will ignore all regdom changes not
+ *     originating from their own wiphy.
+ *     A self-managed wiphys only employs regulatory information obtained from
+ *     the FW and driver and does not use other cfg80211 sources like
+ *     beacon-hints, country-code IEs and hints from other devices on the same
+ *     system. Conversely, a self-managed wiphy does not share its regulatory
+ *     hints with other devices in the system. If a system contains several
+ *     devices, one or more of which are self-managed, there might be
+ *     contradictory regulatory settings between them. Usage of flag is
+ *     generally discouraged. Only use it if the FW/driver is incompatible
+ *     with non-locally originated hints.
+ *     This flag is incompatible with the flags: %REGULATORY_CUSTOM_REG,
+ *     %REGULATORY_STRICT_REG, %REGULATORY_COUNTRY_IE_FOLLOW_POWER,
+ *     %REGULATORY_COUNTRY_IE_IGNORE and %REGULATORY_DISABLE_BEACON_HINTS.
+ *     Mixing any of the above flags with this flag will result in a failure
+ *     to register the wiphy. This flag implies
+ *     %REGULATORY_DISABLE_BEACON_HINTS and %REGULATORY_COUNTRY_IE_IGNORE.
  */
 enum ieee80211_regulatory_flags {
        REGULATORY_CUSTOM_REG                   = BIT(0),
@@ -156,6 +174,7 @@ enum ieee80211_regulatory_flags {
        REGULATORY_COUNTRY_IE_IGNORE            = BIT(4),
        REGULATORY_ENABLE_RELAX_NO_IR           = BIT(5),
        REGULATORY_IGNORE_STALE_KICKOFF         = BIT(6),
+       REGULATORY_WIPHY_SELF_MANAGED           = BIT(7),
 };
 
 struct ieee80211_freq_range {
index b37bd5a..b6c1a00 100644 (file)
 
 #define NL80211_GENL_NAME "nl80211"
 
+#define NL80211_MULTICAST_GROUP_CONFIG         "config"
+#define NL80211_MULTICAST_GROUP_SCAN           "scan"
+#define NL80211_MULTICAST_GROUP_REG            "regulatory"
+#define NL80211_MULTICAST_GROUP_MLME           "mlme"
+#define NL80211_MULTICAST_GROUP_VENDOR         "vendor"
+#define NL80211_MULTICAST_GROUP_TESTMODE       "testmode"
+
 /**
  * DOC: Station handling
  *
  *     %NL80211_ATTR_IFINDEX.
  *
  * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
- *     regulatory domain.
+ *     regulatory domain. If %NL80211_ATTR_WIPHY is specified and the device
+ *     has a private regulatory domain, it will be returned. Otherwise, the
+ *     global regdomain will be returned.
+ *     A device will have a private regulatory domain if it uses the
+ *     regulatory_hint() API. Even when a private regdomain is used the channel
+ *     information will still be mended according to further hints from
+ *     the regulatory core to help with compliance. A dump version of this API
+ *     is now available which will returns the global regdomain as well as
+ *     all private regdomains of present wiphys (for those that have it).
+ *     If a wiphy is self-managed (%NL80211_ATTR_WIPHY_SELF_MANAGED_REG), then
+ *     its private regdomain is the only valid one for it. The regulatory
+ *     core is not used to help with compliance in this case.
  * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
  *     after being queried by the kernel. CRDA replies by sending a regulatory
  *     domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
  *     peer given by %NL80211_ATTR_MAC. Both peers must be on the base channel
  *     when this command completes.
  *
+ * @NL80211_CMD_WIPHY_REG_CHANGE: Similar to %NL80211_CMD_REG_CHANGE, but used
+ *     as an event to indicate changes for devices with wiphy-specific regdom
+ *     management.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -958,6 +980,8 @@ enum nl80211_commands {
        NL80211_CMD_TDLS_CHANNEL_SWITCH,
        NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
 
+       NL80211_CMD_WIPHY_REG_CHANGE,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -1655,6 +1679,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  *     creation then the new interface will be owned by the netlink socket
  *     that created it and will be destroyed when the socket is closed.
+ *     If set during scheduled scan start then the new scan req will be
+ *     owned by the netlink socket that created it and the scheduled scan will
+ *     be stopped when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  *     the TDLS link initiator.
@@ -1688,6 +1715,26 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_MAC_MASK: MAC address mask
  *
+ * @NL80211_ATTR_WIPHY_SELF_MANAGED_REG: flag attribute indicating this device
+ *     is self-managing its regulatory information and any regulatory domain
+ *     obtained from it is coming from the device's wiphy and not the global
+ *     cfg80211 regdomain.
+ *
+ * @NL80211_ATTR_EXT_FEATURES: extended feature flags contained in a byte
+ *     array. The feature flags are identified by their bit index (see &enum
+ *     nl80211_ext_feature_index). The bit index is ordered starting at the
+ *     least-significant bit of the first byte in the array, ie. bit index 0
+ *     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
@@ -2045,6 +2092,12 @@ enum nl80211_attrs {
 
        NL80211_ATTR_MAC_MASK,
 
+       NL80211_ATTR_WIPHY_SELF_MANAGED_REG,
+
+       NL80211_ATTR_EXT_FEATURES,
+
+       NL80211_ATTR_SURVEY_RADIO_STATS,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2085,7 +2138,7 @@ enum nl80211_attrs {
 
 #define NL80211_MAX_SUPP_RATES                 32
 #define NL80211_MAX_SUPP_HT_RATES              77
-#define NL80211_MAX_SUPP_REG_RULES             32
+#define NL80211_MAX_SUPP_REG_RULES             64
 #define NL80211_TKIP_DATA_OFFSET_ENCR_KEY      0
 #define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY    16
 #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY    24
@@ -2285,18 +2338,24 @@ enum nl80211_sta_bss_param {
  *
  * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
  * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
- * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
- * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
- * @NL80211_STA_INFO_RX_BYTES64: total received bytes (u64, from this station)
- * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (u64, to this station)
+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (MPDU length)
+ *     (u32, from this station)
+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (MPDU length)
+ *     (u32, to this station)
+ * @NL80211_STA_INFO_RX_BYTES64: total received bytes (MPDU length)
+ *     (u64, from this station)
+ * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (MPDU length)
+ *     (u64, to this station)
  * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
  * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
  *     containing info as possible, see &enum nl80211_rate_info
- * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
- * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
- *     station)
- * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
- * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (MSDUs and MMPDUs)
+ *     (u32, from this station)
+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (MSDUs and MMPDUs)
+ *     (u32, to this station)
+ * @NL80211_STA_INFO_TX_RETRIES: total retries (MPDUs) (u32, to this station)
+ * @NL80211_STA_INFO_TX_FAILED: total failed packets (MPDUs)
+ *     (u32, to this station)
  * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
  * @NL80211_STA_INFO_LLID: the station's mesh LLID
  * @NL80211_STA_INFO_PLID: the station's mesh PLID
@@ -2320,6 +2379,16 @@ enum nl80211_sta_bss_param {
  *     Same format as NL80211_STA_INFO_CHAIN_SIGNAL.
  * @NL80211_STA_EXPECTED_THROUGHPUT: expected throughput considering also the
  *     802.11 header (u32, kbps)
+ * @NL80211_STA_INFO_RX_DROP_MISC: RX packets dropped for unspecified reasons
+ *     (u64)
+ * @NL80211_STA_INFO_BEACON_RX: number of beacons received from this peer (u64)
+ * @NL80211_STA_INFO_BEACON_SIGNAL_AVG: signal strength average
+ *     for beacons only (u8, dBm)
+ * @NL80211_STA_INFO_TID_STATS: per-TID statistics (see &enum nl80211_tid_stats)
+ *     This is a nested attribute where each the inner attribute number is the
+ *     TID+1 and the special TID 16 (i.e. value 17) is used for non-QoS frames;
+ *     each one of those is again nested with &enum nl80211_tid_stats
+ *     attributes carrying the actual values.
  * @__NL80211_STA_INFO_AFTER_LAST: internal
  * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
@@ -2352,12 +2421,41 @@ enum nl80211_sta_info {
        NL80211_STA_INFO_CHAIN_SIGNAL,
        NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
        NL80211_STA_INFO_EXPECTED_THROUGHPUT,
+       NL80211_STA_INFO_RX_DROP_MISC,
+       NL80211_STA_INFO_BEACON_RX,
+       NL80211_STA_INFO_BEACON_SIGNAL_AVG,
+       NL80211_STA_INFO_TID_STATS,
 
        /* keep last */
        __NL80211_STA_INFO_AFTER_LAST,
        NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_tid_stats - per TID statistics attributes
+ * @__NL80211_TID_STATS_INVALID: attribute number 0 is reserved
+ * @NL80211_TID_STATS_RX_MSDU: number of MSDUs received (u64)
+ * @NL80211_TID_STATS_TX_MSDU: number of MSDUs transmitted (or
+ *     attempted to transmit; u64)
+ * @NL80211_TID_STATS_TX_MSDU_RETRIES: number of retries for
+ *     transmitted MSDUs (not counting the first attempt; u64)
+ * @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
+ *     MSDUs (u64)
+ * @NUM_NL80211_TID_STATS: number of attributes here
+ * @NL80211_TID_STATS_MAX: highest numbered attribute here
+ */
+enum nl80211_tid_stats {
+       __NL80211_TID_STATS_INVALID,
+       NL80211_TID_STATS_RX_MSDU,
+       NL80211_TID_STATS_TX_MSDU,
+       NL80211_TID_STATS_TX_MSDU_RETRIES,
+       NL80211_TID_STATS_TX_MSDU_FAILED,
+
+       /* keep last */
+       NUM_NL80211_TID_STATS,
+       NL80211_TID_STATS_MAX = NUM_NL80211_TID_STATS - 1
+};
+
 /**
  * enum nl80211_mpath_flags - nl80211 mesh path flags
  *
@@ -2772,16 +2870,18 @@ enum nl80211_user_reg_hint_type {
  * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
  * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
  * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
- * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio
- *     spent on this channel
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary
+ * @NL80211_SURVEY_INFO_TIME: amount of time (in ms) that the radio
+ *     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_CHANNEL_TIME_EXT_BUSY: amount of time the extension
+ * @NL80211_SURVEY_INFO_TIME_EXT_BUSY: amount of time the extension
  *     channel was sensed busy
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent
- *     receiving data
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent
- *     transmitting data
+ * @NL80211_SURVEY_INFO_TIME_RX: amount of time the radio spent
+ *     receiving data (on channel or globally)
+ * @NL80211_SURVEY_INFO_TIME_TX: amount of time the radio spent
+ *     transmitting data (on channel or globally)
+ * @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
+ *     (on this channel or globally)
  * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
  *     currently defined
  * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
@@ -2791,17 +2891,25 @@ enum nl80211_survey_info {
        NL80211_SURVEY_INFO_FREQUENCY,
        NL80211_SURVEY_INFO_NOISE,
        NL80211_SURVEY_INFO_IN_USE,
-       NL80211_SURVEY_INFO_CHANNEL_TIME,
-       NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
-       NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
-       NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
-       NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
+       NL80211_SURVEY_INFO_TIME,
+       NL80211_SURVEY_INFO_TIME_BUSY,
+       NL80211_SURVEY_INFO_TIME_EXT_BUSY,
+       NL80211_SURVEY_INFO_TIME_RX,
+       NL80211_SURVEY_INFO_TIME_TX,
+       NL80211_SURVEY_INFO_TIME_SCAN,
 
        /* keep last */
        __NL80211_SURVEY_INFO_AFTER_LAST,
        NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1
 };
 
+/* keep old names for compatibility */
+#define NL80211_SURVEY_INFO_CHANNEL_TIME               NL80211_SURVEY_INFO_TIME
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY          NL80211_SURVEY_INFO_TIME_BUSY
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY      NL80211_SURVEY_INFO_TIME_EXT_BUSY
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_RX            NL80211_SURVEY_INFO_TIME_RX
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_TX            NL80211_SURVEY_INFO_TIME_TX
+
 /**
  * enum nl80211_mntr_flags - monitor configuration flags
  *
@@ -3238,6 +3346,9 @@ enum nl80211_bss {
 /**
  * enum nl80211_bss_status - BSS "status"
  * @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS.
+ *     Note that this is no longer used since cfg80211 no longer
+ *     keeps track of whether or not authentication was done with
+ *     a given BSS.
  * @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS.
  * @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS.
  *
@@ -3623,7 +3734,9 @@ struct nl80211_pattern_support {
  *     same attributes used with @NL80211_CMD_START_SCHED_SCAN.  It
  *     specifies how the scan is performed (e.g. the interval and the
  *     channels to scan) as well as the scan results that will
- *     trigger a wake (i.e. the matchsets).
+ *     trigger a wake (i.e. the matchsets).  This attribute is also
+ *     sent in a response to @NL80211_CMD_GET_WIPHY, indicating the
+ *     number of match sets supported by the driver (u32).
  * @NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS: nested attribute
  *     containing an array with information about what triggered the
  *     wake up.  If no elements are present in the array, it means
@@ -4193,6 +4306,19 @@ enum nl80211_feature_flags {
        NL80211_FEATURE_ND_RANDOM_MAC_ADDR              = 1 << 31,
 };
 
+/**
+ * enum nl80211_ext_feature_index - bit index of extended features.
+ *
+ * @NUM_NL80211_EXT_FEATURES: number of extended features.
+ * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
+ */
+enum nl80211_ext_feature_index {
+
+       /* add new features before the definition below */
+       NUM_NL80211_EXT_FEATURES,
+       MAX_NL80211_EXT_FEATURES = NUM_NL80211_EXT_FEATURES - 1
+};
+
 /**
  * enum nl80211_probe_resp_offload_support_attr - optional supported
  *     protocols for probe-response offloading by the driver/FW.
index e75d5c5..fd6860d 100644 (file)
@@ -678,7 +678,8 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
                      BSS_CHANGED_BEACON_ENABLED |
                      BSS_CHANGED_BEACON |
                      BSS_CHANGED_SSID |
-                     BSS_CHANGED_P2P_PS;
+                     BSS_CHANGED_P2P_PS |
+                     BSS_CHANGED_TXPOWER;
        int err;
 
        old = sdata_dereference(sdata->u.ap.beacon, sdata);
@@ -2556,7 +2557,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
 
        /* if there's one pending or we're scanning, queue this one */
        if (!list_empty(&local->roc_list) ||
-           local->scanning || local->radar_detect_enabled)
+           local->scanning || ieee80211_is_radar_required(local))
                goto out_check_combine;
 
        /* if not HW assist, just queue & schedule work */
@@ -3664,7 +3665,7 @@ static int ieee80211_del_tx_ts(struct wiphy *wiphy, struct net_device *dev,
                 * queues.
                 */
                synchronize_net();
-               ieee80211_flush_queues(local, sdata);
+               ieee80211_flush_queues(local, sdata, false);
 
                /* restore the normal QoS parameters
                 * (unconditionally to avoid races)
index da1c12c..35b11e1 100644 (file)
@@ -388,7 +388,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
        return NULL;
 }
 
-static bool ieee80211_is_radar_required(struct ieee80211_local *local)
+bool ieee80211_is_radar_required(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
 
@@ -406,6 +406,34 @@ static bool ieee80211_is_radar_required(struct ieee80211_local *local)
        return false;
 }
 
+static bool
+ieee80211_chanctx_radar_required(struct ieee80211_local *local,
+                                struct ieee80211_chanctx *ctx)
+{
+       struct ieee80211_chanctx_conf *conf = &ctx->conf;
+       struct ieee80211_sub_if_data *sdata;
+       bool required = false;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+       lockdep_assert_held(&local->mtx);
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+               if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
+                       continue;
+               if (!sdata->radar_required)
+                       continue;
+
+               required = true;
+               break;
+       }
+       rcu_read_unlock();
+
+       return required;
+}
+
 static struct ieee80211_chanctx *
 ieee80211_alloc_chanctx(struct ieee80211_local *local,
                        const struct cfg80211_chan_def *chandef,
@@ -425,7 +453,7 @@ ieee80211_alloc_chanctx(struct ieee80211_local *local,
        ctx->conf.rx_chains_static = 1;
        ctx->conf.rx_chains_dynamic = 1;
        ctx->mode = mode;
-       ctx->conf.radar_enabled = ieee80211_is_radar_required(local);
+       ctx->conf.radar_enabled = false;
        ieee80211_recalc_chanctx_min_def(local, ctx);
 
        return ctx;
@@ -567,16 +595,15 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
        bool radar_enabled;
 
        lockdep_assert_held(&local->chanctx_mtx);
-       /* for setting local->radar_detect_enabled */
+       /* for ieee80211_is_radar_required */
        lockdep_assert_held(&local->mtx);
 
-       radar_enabled = ieee80211_is_radar_required(local);
+       radar_enabled = ieee80211_chanctx_radar_required(local, chanctx);
 
        if (radar_enabled == chanctx->conf.radar_enabled)
                return;
 
        chanctx->conf.radar_enabled = radar_enabled;
-       local->radar_detect_enabled = chanctx->conf.radar_enabled;
 
        if (!local->use_chanctx) {
                local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
index 54a189f..eeb0bbd 100644 (file)
@@ -303,8 +303,6 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf,
                sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n");
        if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE)
                sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n");
-       if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
-               sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n");
        if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
                sf += scnprintf(buf + sf, mxln - sf,
                                "REPORTS_TX_ACK_STATUS\n");
index 2ebc9ea..fdeda17 100644 (file)
@@ -639,6 +639,21 @@ static inline void drv_sta_rate_tbl_update(struct ieee80211_local *local,
        trace_drv_return_void(local);
 }
 
+static inline void drv_sta_statistics(struct ieee80211_local *local,
+                                     struct ieee80211_sub_if_data *sdata,
+                                     struct ieee80211_sta *sta,
+                                     struct station_info *sinfo)
+{
+       sdata = get_bss_sdata(sdata);
+       if (!check_sdata_in_driver(sdata))
+               return;
+
+       trace_drv_sta_statistics(local, sdata, sta);
+       if (local->ops->sta_statistics)
+               local->ops->sta_statistics(&local->hw, &sdata->vif, sta, sinfo);
+       trace_drv_return_void(local);
+}
+
 static inline int drv_conf_tx(struct ieee80211_local *local,
                              struct ieee80211_sub_if_data *sdata, u16 ac,
                              const struct ieee80211_tx_queue_params *params)
@@ -966,21 +981,6 @@ drv_allow_buffered_frames(struct ieee80211_local *local,
        trace_drv_return_void(local);
 }
 
-static inline int drv_get_rssi(struct ieee80211_local *local,
-                               struct ieee80211_sub_if_data *sdata,
-                               struct ieee80211_sta *sta,
-                               s8 *rssi_dbm)
-{
-       int ret;
-
-       might_sleep();
-
-       ret = local->ops->get_rssi(&local->hw, &sdata->vif, sta, rssi_dbm);
-       trace_drv_get_rssi(local, sta, *rssi_dbm, ret);
-
-       return ret;
-}
-
 static inline void drv_mgd_prepare_tx(struct ieee80211_local *local,
                                      struct ieee80211_sub_if_data *sdata)
 {
index ebfc809..52bcea6 100644 (file)
@@ -117,16 +117,16 @@ static void ieee80211_get_stats(struct net_device *dev,
                data[i++] = sta->sta_state;
 
 
-               if (sinfo.filled & STATION_INFO_TX_BITRATE)
+               if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE))
                        data[i] = 100000 *
                                cfg80211_calculate_bitrate(&sinfo.txrate);
                i++;
-               if (sinfo.filled & STATION_INFO_RX_BITRATE)
+               if (sinfo.filled & BIT(NL80211_STA_INFO_RX_BITRATE))
                        data[i] = 100000 *
                                cfg80211_calculate_bitrate(&sinfo.rxrate);
                i++;
 
-               if (sinfo.filled & STATION_INFO_SIGNAL_AVG)
+               if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))
                        data[i] = (u8)sinfo.signal_avg;
                i++;
        } else {
@@ -175,24 +175,24 @@ do_survey:
                data[i++] = (u8)survey.noise;
        else
                data[i++] = -1LL;
-       if (survey.filled & SURVEY_INFO_CHANNEL_TIME)
-               data[i++] = survey.channel_time;
+       if (survey.filled & SURVEY_INFO_TIME)
+               data[i++] = survey.time;
        else
                data[i++] = -1LL;
-       if (survey.filled & SURVEY_INFO_CHANNEL_TIME_BUSY)
-               data[i++] = survey.channel_time_busy;
+       if (survey.filled & SURVEY_INFO_TIME_BUSY)
+               data[i++] = survey.time_busy;
        else
                data[i++] = -1LL;
-       if (survey.filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY)
-               data[i++] = survey.channel_time_ext_busy;
+       if (survey.filled & SURVEY_INFO_TIME_EXT_BUSY)
+               data[i++] = survey.time_ext_busy;
        else
                data[i++] = -1LL;
-       if (survey.filled & SURVEY_INFO_CHANNEL_TIME_RX)
-               data[i++] = survey.channel_time_rx;
+       if (survey.filled & SURVEY_INFO_TIME_RX)
+               data[i++] = survey.time_rx;
        else
                data[i++] = -1LL;
-       if (survey.filled & SURVEY_INFO_CHANNEL_TIME_TX)
-               data[i++] = survey.channel_time_tx;
+       if (survey.filled & SURVEY_INFO_TIME_TX)
+               data[i++] = survey.time_tx;
        else
                data[i++] = -1LL;
 
index 509bc15..b606b53 100644 (file)
@@ -1069,9 +1069,16 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                }
 
                if (sta && rates_updated) {
-                       drv_sta_rc_update(local, sdata, &sta->sta,
-                                         IEEE80211_RC_SUPP_RATES_CHANGED);
+                       u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
+                       u8 rx_nss = sta->sta.rx_nss;
+
+                       /* Force rx_nss recalculation */
+                       sta->sta.rx_nss = 0;
                        rate_control_rate_init(sta);
+                       if (sta->sta.rx_nss != rx_nss)
+                               changed |= IEEE80211_RC_NSS_CHANGED;
+
+                       drv_sta_rc_update(local, sdata, &sta->sta, changed);
                }
 
                rcu_read_unlock();
index cc6e964..156ea79 100644 (file)
@@ -1168,8 +1168,6 @@ struct ieee80211_local {
        /* wowlan is enabled -- don't reconfig on resume */
        bool wowlan;
 
-       /* DFS/radar detection is enabled */
-       bool radar_detect_enabled;
        struct work_struct radar_detected_work;
 
        /* number of RX chains the hardware has */
@@ -1704,6 +1702,7 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_supported_band *sband,
                                    const struct ieee80211_vht_cap *vht_cap_ie,
                                    struct sta_info *sta);
+enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta);
 enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta);
 void ieee80211_sta_set_rx_nss(struct sta_info *sta);
 u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
@@ -1881,10 +1880,10 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
 void ieee80211_add_pending_skbs(struct ieee80211_local *local,
                                struct sk_buff_head *skbs);
 void ieee80211_flush_queues(struct ieee80211_local *local,
-                           struct ieee80211_sub_if_data *sdata);
+                           struct ieee80211_sub_if_data *sdata, bool drop);
 void __ieee80211_flush_queues(struct ieee80211_local *local,
                              struct ieee80211_sub_if_data *sdata,
-                             unsigned int queues);
+                             unsigned int queues, bool drop);
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
                         u16 transaction, u16 auth_alg, u16 status,
@@ -1981,6 +1980,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
                                   struct ieee80211_chanctx *chanctx);
 void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
                                      struct ieee80211_chanctx *ctx);
+bool ieee80211_is_radar_required(struct ieee80211_local *local);
 
 void ieee80211_dfs_cac_timer(unsigned long data);
 void ieee80211_dfs_cac_timer_work(struct work_struct *work);
index 4173553..677422e 100644 (file)
@@ -93,7 +93,7 @@ static u32 __ieee80211_idle_on(struct ieee80211_local *local)
        if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
                return 0;
 
-       ieee80211_flush_queues(local, NULL);
+       ieee80211_flush_queues(local, NULL, false);
 
        local->hw.conf.flags |= IEEE80211_CONF_IDLE;
        return IEEE80211_CONF_CHANGE_IDLE;
index bd4e46e..f8d9f0e 100644 (file)
@@ -141,8 +141,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 
                if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+                     (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
                        sdata->crypto_tx_tailroom_needed_cnt--;
 
                WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
@@ -191,8 +190,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
        sdata = key->sdata;
 
        if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-             (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
-             (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+             (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
                increment_tailroom_need_count(sdata);
 
        ret = drv_set_key(key->local, DISABLE_KEY, sdata,
@@ -889,8 +887,7 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf)
                key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 
                if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
+                     (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
                        increment_tailroom_need_count(key->sdata);
        }
 
index 6ab99da..d9ce336 100644 (file)
@@ -916,10 +916,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                }
        }
 
-       WARN((local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
-            && (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK),
-            "U-APSD not supported with HW_PS_NULLFUNC_STACK\n");
-
        /*
         * Calculate scan IE length -- we need this to alloc
         * memory and to subtract from the driver limit. It
index b488e18..fa94ca1 100644 (file)
@@ -523,6 +523,13 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
            sdata->u.mesh.mshcfg.auto_open_plinks &&
            rssi_threshold_check(sdata, sta))
                changed = mesh_plink_open(sta);
+       else if (sta->plink_state == NL80211_PLINK_LISTEN &&
+                (sdata->u.mesh.user_mpm ||
+                 sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED))
+               cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
+                                                  elems->ie_start,
+                                                  elems->total_len,
+                                                  GFP_ATOMIC);
 
        ieee80211_mps_frame_release(sta, elems);
 out:
index 2c36c47..c071108 100644 (file)
@@ -157,14 +157,18 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct cfg80211_chan_def vht_chandef;
+       struct ieee80211_sta_ht_cap sta_ht_cap;
        u32 ht_cfreq, ret;
 
+       memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
+       ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
+
        chandef->chan = channel;
        chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
        chandef->center_freq1 = channel->center_freq;
        chandef->center_freq2 = 0;
 
-       if (!ht_cap || !ht_oper || !sband->ht_cap.ht_supported) {
+       if (!ht_cap || !ht_oper || !sta_ht_cap.ht_supported) {
                ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
                goto out;
        }
@@ -198,7 +202,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
        }
 
        /* check 40 MHz support, if we have it */
-       if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+       if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
                switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
                case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
                        chandef->width = NL80211_CHAN_WIDTH_40;
@@ -1054,8 +1058,6 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
                sdata->csa_block_tx = false;
        }
 
-       cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef);
-
        sdata->vif.csa_active = false;
        ifmgd->csa_waiting_bcn = false;
 
@@ -1067,6 +1069,8 @@ static void ieee80211_chswitch_post_beacon(struct ieee80211_sub_if_data *sdata)
                                     &ifmgd->csa_connection_drop_work);
                return;
        }
+
+       cfg80211_ch_switch_notify(sdata->dev, &sdata->reserved_chandef);
 }
 
 void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success)
@@ -1284,8 +1288,11 @@ ieee80211_find_80211h_pwr_constr(struct ieee80211_sub_if_data *sdata,
                country_ie_len -= 3;
        }
 
-       if (have_chan_pwr)
+       if (have_chan_pwr && pwr_constr_elem)
                *pwr_reduction = *pwr_constr_elem;
+       else
+               *pwr_reduction = 0;
+
        return have_chan_pwr;
 }
 
@@ -1314,10 +1321,11 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
        int chan_pwr = 0, pwr_reduction_80211h = 0;
        int pwr_level_cisco, pwr_level_80211h;
        int new_ap_level;
+       __le16 capab = mgmt->u.probe_resp.capab_info;
 
-       if (country_ie && pwr_constr_ie &&
-           mgmt->u.probe_resp.capab_info &
-               cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT)) {
+       if (country_ie &&
+           (capab & cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT) ||
+            capab & cpu_to_le16(WLAN_CAPABILITY_RADIO_MEASURE))) {
                has_80211h_pwr = ieee80211_find_80211h_pwr_constr(
                        sdata, channel, country_ie, country_ie_len,
                        pwr_constr_ie, &chan_pwr, &pwr_reduction_80211h);
@@ -1596,7 +1604,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
                } else {
                        ieee80211_send_nullfunc(local, sdata, 1);
                        /* Flush to get the tx status of nullfunc frame */
-                       ieee80211_flush_queues(local, sdata);
+                       ieee80211_flush_queues(local, sdata, false);
                }
        }
 
@@ -2003,18 +2011,23 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        /* disable per-vif ps */
        ieee80211_recalc_ps_vif(sdata);
 
-       /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */
+       /*
+        * drop any frame before deauth/disassoc, this can be data or
+        * management frame. Since we are disconnecting, we should not
+        * insist sending these frames which can take time and delay
+        * the disconnection and possible the roaming.
+        */
        if (tx)
-               ieee80211_flush_queues(local, sdata);
+               ieee80211_flush_queues(local, sdata, true);
 
        /* deauthenticate/disassociate now */
        if (tx || frame_buf)
                ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype,
                                               reason, tx, frame_buf);
 
-       /* flush out frame */
+       /* flush out frame - make sure the deauth was actually sent */
        if (tx)
-               ieee80211_flush_queues(local, sdata);
+               ieee80211_flush_queues(local, sdata, false);
 
        /* clear bssid only after building the needed mgmt frames */
        memset(ifmgd->bssid, 0, ETH_ALEN);
@@ -4197,9 +4210,13 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_bss *bss = (void *)cbss->priv;
        struct sta_info *new_sta = NULL;
-       bool have_sta = false;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_sta_ht_cap sta_ht_cap;
+       bool have_sta = false, is_override = false;
        int err;
 
+       sband = local->hw.wiphy->bands[cbss->channel->band];
+
        if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data))
                return -EINVAL;
 
@@ -4214,25 +4231,32 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
                if (!new_sta)
                        return -ENOMEM;
        }
+
+       memcpy(&sta_ht_cap, &sband->ht_cap, sizeof(sta_ht_cap));
+       ieee80211_apply_htcap_overrides(sdata, &sta_ht_cap);
+
+       is_override = (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) !=
+                     (sband->ht_cap.cap &
+                      IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+
+       if (new_sta || is_override) {
+               err = ieee80211_prep_channel(sdata, cbss);
+               if (err) {
+                       if (new_sta)
+                               sta_info_free(local, new_sta);
+                       return -EINVAL;
+               }
+       }
+
        if (new_sta) {
                u32 rates = 0, basic_rates = 0;
                bool have_higher_than_11mbit;
                int min_rate = INT_MAX, min_rate_index = -1;
                struct ieee80211_chanctx_conf *chanctx_conf;
-               struct ieee80211_supported_band *sband;
                const struct cfg80211_bss_ies *ies;
-               int shift;
+               int shift = ieee80211_vif_get_shift(&sdata->vif);
                u32 rate_flags;
 
-               sband = local->hw.wiphy->bands[cbss->channel->band];
-
-               err = ieee80211_prep_channel(sdata, cbss);
-               if (err) {
-                       sta_info_free(local, new_sta);
-                       return -EINVAL;
-               }
-               shift = ieee80211_vif_get_shift(&sdata->vif);
-
                rcu_read_lock();
                chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
                if (WARN_ON(!chanctx_conf)) {
@@ -4668,8 +4692,13 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
        rcu_read_unlock();
 
+       if (WARN((sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD) &&
+                (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK),
+            "U-APSD not supported with HW_PS_NULLFUNC_STACK\n"))
+               sdata->vif.driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
+
        if (bss->wmm_used && bss->uapsd_supported &&
-           (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
+           (sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_UAPSD)) {
                assoc_data->uapsd = true;
                ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED;
        } else {
index ff20b2e..683f0e3 100644 (file)
@@ -121,7 +121,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
        ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL,
                                        false);
-       ieee80211_flush_queues(local, NULL);
+       ieee80211_flush_queues(local, NULL, false);
 
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry(sdata, &local->interfaces, list) {
@@ -398,7 +398,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
                ieee80211_roc_notify_destroy(roc, !roc->abort);
 
                if (started && !on_channel) {
-                       ieee80211_flush_queues(local, NULL);
+                       ieee80211_flush_queues(local, NULL, false);
 
                        local->tmp_channel = NULL;
                        ieee80211_hw_config(local, 0);
index 4c5192e..8c8c678 100644 (file)
@@ -41,7 +41,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        /* flush out all packets */
        synchronize_net();
 
-       ieee80211_flush_queues(local, NULL);
+       ieee80211_flush_queues(local, NULL, true);
 
        local->quiescing = true;
        /* make quiescing visible to timers everywhere */
index d51f6b1..7c86a00 100644 (file)
@@ -263,12 +263,12 @@ static inline unsigned int
 minstrel_get_retry_count(struct minstrel_rate *mr,
                         struct ieee80211_tx_info *info)
 {
-       unsigned int retry = mr->adjusted_retry_count;
+       u8 retry = mr->adjusted_retry_count;
 
        if (info->control.use_rts)
-               retry = max(2U, min(mr->stats.retry_count_rtscts, retry));
+               retry = max_t(u8, 2, min(mr->stats.retry_count_rtscts, retry));
        else if (info->control.use_cts_prot)
-               retry = max(2U, min(mr->retry_count_cts, retry));
+               retry = max_t(u8, 2, min(mr->retry_count_cts, retry));
        return retry;
 }
 
index 97eca86..410efe6 100644 (file)
@@ -33,8 +33,8 @@ minstrel_ewma(int old, int new, int weight)
 
 struct minstrel_rate_stats {
        /* current / last sampling period attempts/success counters */
-       unsigned int attempts, last_attempts;
-       unsigned int success, last_success;
+       u16 attempts, last_attempts;
+       u16 success, last_success;
 
        /* total attempts/success counters */
        u64 att_hist, succ_hist;
@@ -46,8 +46,8 @@ struct minstrel_rate_stats {
        unsigned int cur_prob, probability;
 
        /* maximum retry counts */
-       unsigned int retry_count;
-       unsigned int retry_count_rtscts;
+       u8 retry_count;
+       u8 retry_count_rtscts;
 
        u8 sample_skipped;
        bool retry_updated;
@@ -55,14 +55,15 @@ struct minstrel_rate_stats {
 
 struct minstrel_rate {
        int bitrate;
-       int rix;
+
+       s8 rix;
+       u8 retry_count_cts;
+       u8 adjusted_retry_count;
 
        unsigned int perfect_tx_time;
        unsigned int ack_time;
 
        int sample_limit;
-       unsigned int retry_count_cts;
-       unsigned int adjusted_retry_count;
 
        struct minstrel_rate_stats stats;
 };
index 683b10f..3a1a3ba 100644 (file)
@@ -2314,6 +2314,15 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
        if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
                return RX_DROP_MONITOR;
 
+       if (rx->sta) {
+               /* The security index has the same property as needed
+                * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS
+                * for non-QoS-data frames. Here we know it's a data
+                * frame, so count MSDUs.
+                */
+               rx->sta->rx_msdu[rx->security_idx]++;
+       }
+
        /*
         * Send unexpected-4addr-frame event to hostapd. For older versions,
         * also drop the frame to cooked monitor interfaces.
@@ -2598,7 +2607,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                case WLAN_HT_ACTION_NOTIFY_CHANWIDTH: {
                        struct ieee80211_supported_band *sband;
                        u8 chanwidth = mgmt->u.action.u.ht_notify_cw.chanwidth;
-                       enum ieee80211_sta_rx_bandwidth new_bw;
+                       enum ieee80211_sta_rx_bandwidth max_bw, new_bw;
 
                        /* If it doesn't support 40 MHz it can't change ... */
                        if (!(rx->sta->sta.ht_cap.cap &
@@ -2606,13 +2615,18 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                                goto handled;
 
                        if (chanwidth == IEEE80211_HT_CHANWIDTH_20MHZ)
-                               new_bw = IEEE80211_STA_RX_BW_20;
+                               max_bw = IEEE80211_STA_RX_BW_20;
                        else
-                               new_bw = ieee80211_sta_cur_vht_bw(rx->sta);
+                               max_bw = ieee80211_sta_cap_rx_bw(rx->sta);
+
+                       /* set cur_max_bandwidth and recalc sta bw */
+                       rx->sta->cur_max_bandwidth = max_bw;
+                       new_bw = ieee80211_sta_cur_vht_bw(rx->sta);
 
                        if (rx->sta->sta.bandwidth == new_bw)
                                goto handled;
 
+                       rx->sta->sta.bandwidth = new_bw;
                        sband = rx->local->hw.wiphy->bands[status->band];
 
                        rate_control_rate_update(local, sband, rx->sta,
index ae84267..7807fa4 100644 (file)
@@ -416,7 +416,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local,
        ieee80211_offchannel_stop_vifs(local);
 
        /* ensure nullfunc is transmitted before leaving operating channel */
-       ieee80211_flush_queues(local, NULL);
+       ieee80211_flush_queues(local, NULL, false);
 
        ieee80211_configure_filter(local);
 
@@ -432,7 +432,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local,
 static bool ieee80211_can_scan(struct ieee80211_local *local,
                               struct ieee80211_sub_if_data *sdata)
 {
-       if (local->radar_detect_enabled)
+       if (ieee80211_is_radar_required(local))
                return false;
 
        if (!list_empty(&local->roc_list))
@@ -505,7 +505,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 
        lockdep_assert_held(&local->mtx);
 
-       if (local->scan_req)
+       if (local->scan_req || ieee80211_is_radar_required(local))
                return -EBUSY;
 
        if (!ieee80211_can_scan(local, sdata)) {
@@ -805,7 +805,7 @@ static void ieee80211_scan_state_resume(struct ieee80211_local *local,
        ieee80211_offchannel_stop_vifs(local);
 
        if (local->ops->flush) {
-               ieee80211_flush_queues(local, NULL);
+               ieee80211_flush_queues(local, NULL, false);
                *next_delay = 0;
        } else
                *next_delay = HZ / 10;
index efeba56..06e6ac8 100644 (file)
@@ -34,19 +34,15 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
        struct cfg80211_chan_def new_vht_chandef = {};
        const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
        const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
-       const struct ieee80211_ht_operation *ht_oper;
        int secondary_channel_offset = -1;
 
        sec_chan_offs = elems->sec_chan_offs;
        wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
-       ht_oper = elems->ht_operation;
 
        if (sta_flags & (IEEE80211_STA_DISABLE_HT |
                         IEEE80211_STA_DISABLE_40MHZ)) {
                sec_chan_offs = NULL;
                wide_bw_chansw_ie = NULL;
-               /* only used for bandwidth here */
-               ht_oper = NULL;
        }
 
        if (sta_flags & IEEE80211_STA_DISABLE_VHT)
index a42f5b2..79383ef 100644 (file)
@@ -116,7 +116,6 @@ static void __cleanup_single_sta(struct sta_info *sta)
                clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
 
                atomic_dec(&ps->num_sta_ps);
-               sta_info_recalc_tim(sta);
        }
 
        for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
@@ -625,7 +624,7 @@ static unsigned long ieee80211_tids_for_ac(int ac)
        }
 }
 
-void sta_info_recalc_tim(struct sta_info *sta)
+static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending)
 {
        struct ieee80211_local *local = sta->local;
        struct ps_data *ps;
@@ -667,6 +666,9 @@ void sta_info_recalc_tim(struct sta_info *sta)
        if (ignore_for_tim == BIT(IEEE80211_NUM_ACS) - 1)
                ignore_for_tim = 0;
 
+       if (ignore_pending)
+               ignore_for_tim = BIT(IEEE80211_NUM_ACS) - 1;
+
        for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
                unsigned long tids;
 
@@ -695,7 +697,7 @@ void sta_info_recalc_tim(struct sta_info *sta)
        else
                __bss_tim_clear(ps->tim, id);
 
-       if (local->ops->set_tim) {
+       if (local->ops->set_tim && !WARN_ON(sta->dead)) {
                local->tim_in_locked_section = true;
                drv_set_tim(local, &sta->sta, indicate_tim);
                local->tim_in_locked_section = false;
@@ -705,6 +707,11 @@ out_unlock:
        spin_unlock_bh(&local->tim_lock);
 }
 
+void sta_info_recalc_tim(struct sta_info *sta)
+{
+       __sta_info_recalc_tim(sta, false);
+}
+
 static bool sta_info_buffer_expired(struct sta_info *sta, struct sk_buff *skb)
 {
        struct ieee80211_tx_info *info;
@@ -874,6 +881,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
 {
        struct ieee80211_local *local = sta->local;
        struct ieee80211_sub_if_data *sdata = sta->sdata;
+       struct station_info sinfo = {};
        int ret;
 
        /*
@@ -887,6 +895,9 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
        /* now keys can no longer be reached */
        ieee80211_free_sta_keys(local, sta);
 
+       /* disable TIM bit - last chance to tell driver */
+       __sta_info_recalc_tim(sta, true);
+
        sta->dead = true;
 
        local->num_sta--;
@@ -908,7 +919,8 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
 
        sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
 
-       cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL);
+       sta_set_sinfo(sta, &sinfo);
+       cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
 
        rate_control_remove_sta_debugfs(sta);
        ieee80211_sta_debugfs_remove(sta);
@@ -1243,10 +1255,11 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
         * ends the poll/service period.
         */
        info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
-                      IEEE80211_TX_CTL_PS_RESPONSE |
                       IEEE80211_TX_STATUS_EOSP |
                       IEEE80211_TX_CTL_REQ_TX_STATUS;
 
+       info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE;
+
        if (call_driver)
                drv_allow_buffered_frames(local, sta, BIT(tid), 1,
                                          reason, false);
@@ -1395,8 +1408,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
                         * STA may still remain is PS mode after this frame
                         * exchange.
                         */
-                       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER |
-                                      IEEE80211_TX_CTL_PS_RESPONSE;
+                       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+                       info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE;
 
                        /*
                         * Use MoreData flag to indicate whether there are
@@ -1743,7 +1756,6 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
        struct ieee80211_local *local = sdata->local;
        struct rate_control_ref *ref = NULL;
        struct timespec uptime;
-       u64 packets = 0;
        u32 thr = 0;
        int i, ac;
 
@@ -1752,49 +1764,76 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 
        sinfo->generation = sdata->local->sta_generation;
 
-       sinfo->filled = STATION_INFO_INACTIVE_TIME |
-                       STATION_INFO_RX_BYTES64 |
-                       STATION_INFO_TX_BYTES64 |
-                       STATION_INFO_RX_PACKETS |
-                       STATION_INFO_TX_PACKETS |
-                       STATION_INFO_TX_RETRIES |
-                       STATION_INFO_TX_FAILED |
-                       STATION_INFO_TX_BITRATE |
-                       STATION_INFO_RX_BITRATE |
-                       STATION_INFO_RX_DROP_MISC |
-                       STATION_INFO_BSS_PARAM |
-                       STATION_INFO_CONNECTED_TIME |
-                       STATION_INFO_STA_FLAGS |
-                       STATION_INFO_BEACON_LOSS_COUNT;
+       drv_sta_statistics(local, sdata, &sta->sta, sinfo);
+
+       sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME) |
+                        BIT(NL80211_STA_INFO_STA_FLAGS) |
+                        BIT(NL80211_STA_INFO_BSS_PARAM) |
+                        BIT(NL80211_STA_INFO_CONNECTED_TIME) |
+                        BIT(NL80211_STA_INFO_RX_DROP_MISC) |
+                        BIT(NL80211_STA_INFO_BEACON_LOSS);
 
        ktime_get_ts(&uptime);
        sinfo->connected_time = uptime.tv_sec - sta->last_connected;
-
        sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
-       sinfo->tx_bytes = 0;
-       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-               sinfo->tx_bytes += sta->tx_bytes[ac];
-               packets += sta->tx_packets[ac];
+
+       if (!(sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES64) |
+                              BIT(NL80211_STA_INFO_TX_BYTES)))) {
+               sinfo->tx_bytes = 0;
+               for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+                       sinfo->tx_bytes += sta->tx_bytes[ac];
+               sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64);
+       }
+
+       if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_PACKETS))) {
+               sinfo->tx_packets = 0;
+               for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+                       sinfo->tx_packets += sta->tx_packets[ac];
+               sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
+       }
+
+       if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) |
+                              BIT(NL80211_STA_INFO_RX_BYTES)))) {
+               sinfo->rx_bytes = sta->rx_bytes;
+               sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
+       }
+
+       if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_PACKETS))) {
+               sinfo->rx_packets = sta->rx_packets;
+               sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
+       }
+
+       if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_RETRIES))) {
+               sinfo->tx_retries = sta->tx_retry_count;
+               sinfo->filled |= BIT(NL80211_STA_INFO_TX_RETRIES);
        }
-       sinfo->tx_packets = packets;
-       sinfo->rx_bytes = sta->rx_bytes;
-       sinfo->rx_packets = sta->rx_packets;
-       sinfo->tx_retries = sta->tx_retry_count;
-       sinfo->tx_failed = sta->tx_retry_failed;
+
+       if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_FAILED))) {
+               sinfo->tx_failed = sta->tx_retry_failed;
+               sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED);
+       }
+
        sinfo->rx_dropped_misc = sta->rx_dropped;
        sinfo->beacon_loss_count = sta->beacon_loss_count;
 
        if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) ||
            (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) {
-               sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
-               if (!local->ops->get_rssi ||
-                   drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal))
+               if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL))) {
                        sinfo->signal = (s8)sta->last_signal;
-               sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
+                       sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
+               }
+
+               if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))) {
+                       sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
+                       sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
+               }
        }
-       if (sta->chains) {
-               sinfo->filled |= STATION_INFO_CHAIN_SIGNAL |
-                                STATION_INFO_CHAIN_SIGNAL_AVG;
+
+       if (sta->chains &&
+           !(sinfo->filled & (BIT(NL80211_STA_INFO_CHAIN_SIGNAL) |
+                              BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) {
+               sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL) |
+                                BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
 
                sinfo->chains = sta->chains;
                for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
@@ -1804,23 +1843,61 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                }
        }
 
-       sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
-       sta_set_rate_info_rx(sta, &sinfo->rxrate);
+       if (!(sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE))) {
+               sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
+               sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
+       }
+
+       if (!(sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE))) {
+               sta_set_rate_info_rx(sta, &sinfo->rxrate);
+               sinfo->filled |= BIT(NL80211_STA_INFO_RX_BITRATE);
+       }
+
+       sinfo->filled |= BIT(NL80211_STA_INFO_TID_STATS);
+       for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
+               struct cfg80211_tid_stats *tidstats = &sinfo->pertid[i];
+
+               if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) {
+                       tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU);
+                       tidstats->rx_msdu = sta->rx_msdu[i];
+               }
+
+               if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) {
+                       tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU);
+                       tidstats->tx_msdu = sta->tx_msdu[i];
+               }
+
+               if (!(tidstats->filled &
+                               BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) &&
+                   local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
+                       tidstats->filled |=
+                               BIT(NL80211_TID_STATS_TX_MSDU_RETRIES);
+                       tidstats->tx_msdu_retries = sta->tx_msdu_retries[i];
+               }
+
+               if (!(tidstats->filled &
+                               BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) &&
+                   local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) {
+                       tidstats->filled |=
+                               BIT(NL80211_TID_STATS_TX_MSDU_FAILED);
+                       tidstats->tx_msdu_failed = sta->tx_msdu_failed[i];
+               }
+       }
 
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
 #ifdef CONFIG_MAC80211_MESH
-               sinfo->filled |= STATION_INFO_LLID |
-                                STATION_INFO_PLID |
-                                STATION_INFO_PLINK_STATE |
-                                STATION_INFO_LOCAL_PM |
-                                STATION_INFO_PEER_PM |
-                                STATION_INFO_NONPEER_PM;
+               sinfo->filled |= BIT(NL80211_STA_INFO_LLID) |
+                                BIT(NL80211_STA_INFO_PLID) |
+                                BIT(NL80211_STA_INFO_PLINK_STATE) |
+                                BIT(NL80211_STA_INFO_LOCAL_PM) |
+                                BIT(NL80211_STA_INFO_PEER_PM) |
+                                BIT(NL80211_STA_INFO_NONPEER_PM);
 
                sinfo->llid = sta->llid;
                sinfo->plid = sta->plid;
                sinfo->plink_state = sta->plink_state;
                if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {
-                       sinfo->filled |= STATION_INFO_T_OFFSET;
+                       sinfo->filled |= BIT(NL80211_STA_INFO_T_OFFSET);
                        sinfo->t_offset = sta->t_offset;
                }
                sinfo->local_pm = sta->local_pm;
@@ -1869,7 +1946,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                thr = drv_get_expected_throughput(local, &sta->sta);
 
        if (thr != 0) {
-               sinfo->filled |= STATION_INFO_EXPECTED_THROUGHPUT;
+               sinfo->filled |= BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT);
                sinfo->expected_throughput = thr;
        }
 }
index 4f052bb..925e68f 100644 (file)
@@ -346,6 +346,14 @@ struct ieee80211_tx_latency_stat {
  * @cipher_scheme: optional cipher scheme for this station
  * @last_tdls_pkt_time: holds the time in jiffies of last TDLS pkt ACKed
  * @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED)
+ * @tx_msdu: MSDUs transmitted to this station, using IEEE80211_NUM_TID
+ *     entry for non-QoS frames
+ * @tx_msdu_retries: MSDU retries for transmissions to to this station,
+ *     using IEEE80211_NUM_TID entry for non-QoS frames
+ * @tx_msdu_failed: MSDU failures for transmissions to to this station,
+ *     using IEEE80211_NUM_TID entry for non-QoS frames
+ * @rx_msdu: MSDUs received from this station, using IEEE80211_NUM_TID
+ *     entry for non-QoS frames
  */
 struct sta_info {
        /* General information, mostly static */
@@ -416,6 +424,10 @@ struct sta_info {
        u32 last_rx_rate_vht_flag;
        u8 last_rx_rate_vht_nss;
        u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
+       u64 tx_msdu[IEEE80211_NUM_TIDS + 1];
+       u64 tx_msdu_retries[IEEE80211_NUM_TIDS + 1];
+       u64 tx_msdu_failed[IEEE80211_NUM_TIDS + 1];
+       u64 rx_msdu[IEEE80211_NUM_TIDS + 1];
 
        /*
         * Aggregation information, locked with lock.
index bb146f3..788707f 100644 (file)
@@ -664,13 +664,15 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
        struct ieee80211_supported_band *sband;
        int retry_count;
        int rates_idx;
-       bool acked;
+       bool acked, noack_success;
 
        rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
 
        sband = hw->wiphy->bands[info->band];
 
        acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
+       noack_success = !!(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED);
+
        if (pubsta) {
                struct sta_info *sta;
 
@@ -696,7 +698,7 @@ void ieee80211_tx_status_noskb(struct ieee80211_hw *hw,
                rate_control_tx_status_noskb(local, sband, sta, info);
        }
 
-       if (acked) {
+       if (acked || noack_success) {
                    local->dot11TransmittedFrameCount++;
                    if (!pubsta)
                            local->dot11MulticastTransmittedFrameCount++;
@@ -728,6 +730,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        struct ieee80211_bar *bar;
        int rtap_len;
        int shift = 0;
+       int tid = IEEE80211_NUM_TIDS;;
 
        rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
 
@@ -771,7 +774,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
                if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
                    (ieee80211_is_data_qos(fc))) {
-                       u16 tid, ssn;
+                       u16 ssn;
                        u8 *qc;
 
                        qc = ieee80211_get_qos_ctl(hdr);
@@ -780,10 +783,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                                                & IEEE80211_SCTL_SEQ);
                        ieee80211_send_bar(&sta->sdata->vif, hdr->addr1,
                                           tid, ssn);
+               } else if (ieee80211_is_data_qos(fc)) {
+                       u8 *qc = ieee80211_get_qos_ctl(hdr);
+
+                       tid = qc[0] & 0xf;
                }
 
                if (!acked && ieee80211_is_back_req(fc)) {
-                       u16 tid, control;
+                       u16 control;
 
                        /*
                         * BAR failed, store the last SSN and retry sending
@@ -811,6 +818,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                        if (!acked)
                                sta->tx_retry_failed++;
                        sta->tx_retry_count += retry_count;
+
+                       if (ieee80211_is_data_present(fc)) {
+                               if (!acked)
+                                       sta->tx_msdu_failed[tid]++;
+                               sta->tx_msdu_retries[tid] += retry_count;
+                       }
                }
 
                rate_control_tx_status(local, sband, sta, skb);
@@ -856,10 +869,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
         * Fragments are passed to low-level drivers as separate skbs, so these
         * are actually fragments, not frames. Update frame counters only for
         * the first fragment of the frame. */
-       if (info->flags & IEEE80211_TX_STAT_ACK) {
+       if ((info->flags & IEEE80211_TX_STAT_ACK) ||
+           (info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED)) {
                if (ieee80211_is_first_frag(hdr->seq_ctrl)) {
                        local->dot11TransmittedFrameCount++;
-                       if (is_multicast_ether_addr(hdr->addr1))
+                       if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
                                local->dot11MulticastTransmittedFrameCount++;
                        if (retry_count > 0)
                                local->dot11RetryCount++;
index 55ddd77..917088d 100644 (file)
@@ -68,17 +68,24 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata,
                ch = ieee80211_get_channel(sdata->local->hw.wiphy, i);
                if (ch) {
                        /* we will be active on the channel */
-                       u32 flags = IEEE80211_CHAN_DISABLED |
-                                   IEEE80211_CHAN_NO_IR;
                        cfg80211_chandef_create(&chandef, ch,
-                                               NL80211_CHAN_HT20);
-                       if (cfg80211_chandef_usable(sdata->local->hw.wiphy,
-                                                   &chandef, flags)) {
+                                               NL80211_CHAN_NO_HT);
+                       if (cfg80211_reg_can_beacon(sdata->local->hw.wiphy,
+                                                   &chandef,
+                                                   sdata->wdev.iftype)) {
                                ch_cnt++;
+                               /*
+                                * check if the next channel is also part of
+                                * this allowed range
+                                */
                                continue;
                        }
                }
 
+               /*
+                * we've reached the end of a range, with allowed channels
+                * found
+                */
                if (ch_cnt) {
                        u8 *pos = skb_put(skb, 2);
                        *pos++ = ieee80211_frequency_to_channel(subband_start);
@@ -89,6 +96,15 @@ ieee80211_tdls_add_subband(struct ieee80211_sub_if_data *sdata,
                }
        }
 
+       /* all channels in the requested range are allowed - add them here */
+       if (ch_cnt) {
+               u8 *pos = skb_put(skb, 2);
+               *pos++ = ieee80211_frequency_to_channel(subband_start);
+               *pos++ = ch_cnt;
+
+               subband_cnt++;
+       }
+
        return subband_cnt;
 }
 
@@ -912,7 +928,7 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
                rcu_read_unlock();
        }
 
-       ieee80211_flush_queues(local, sdata);
+       ieee80211_flush_queues(local, sdata, false);
 
        ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
                                              dialog_token, status_code,
@@ -952,7 +968,7 @@ ieee80211_tdls_mgmt_teardown(struct wiphy *wiphy, struct net_device *dev,
         */
        ieee80211_stop_vif_queues(local, sdata,
                                  IEEE80211_QUEUE_STOP_REASON_TDLS_TEARDOWN);
-       ieee80211_flush_queues(local, sdata);
+       ieee80211_flush_queues(local, sdata, false);
 
        ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, action_code,
                                              dialog_token, status_code,
@@ -1098,7 +1114,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
                 */
                tasklet_kill(&local->tx_pending_tasklet);
                /* flush a potentially queued teardown packet */
-               ieee80211_flush_queues(local, sdata);
+               ieee80211_flush_queues(local, sdata, false);
 
                ret = sta_info_destroy_addr(sdata, peer);
                break;
index 8e461a0..263a956 100644 (file)
@@ -825,6 +825,13 @@ DECLARE_EVENT_CLASS(sta_event,
        )
 );
 
+DEFINE_EVENT(sta_event, drv_sta_statistics,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_sta *sta),
+       TP_ARGS(local, sdata, sta)
+);
+
 DEFINE_EVENT(sta_event, drv_sta_add,
        TP_PROTO(struct ieee80211_local *local,
                 struct ieee80211_sub_if_data *sdata,
@@ -1329,32 +1336,6 @@ DEFINE_EVENT(release_evt, drv_allow_buffered_frames,
        TP_ARGS(local, sta, tids, num_frames, reason, more_data)
 );
 
-TRACE_EVENT(drv_get_rssi,
-       TP_PROTO(struct ieee80211_local *local, struct ieee80211_sta *sta,
-                s8 rssi, int ret),
-
-       TP_ARGS(local, sta, rssi, ret),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               STA_ENTRY
-               __field(s8, rssi)
-               __field(int, ret)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               STA_ASSIGN;
-               __entry->rssi = rssi;
-               __entry->ret = ret;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT STA_PR_FMT " rssi:%d ret:%d",
-               LOCAL_PR_ARG, STA_PR_ARG, __entry->rssi, __entry->ret
-       )
-);
-
 DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx,
        TP_PROTO(struct ieee80211_local *local,
                 struct ieee80211_sub_if_data *sdata),
index 058686a..02ed6f6 100644 (file)
@@ -815,6 +815,8 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
                /* for pure STA mode without beacons, we can do it */
                hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number);
                tx->sdata->sequence_number += 0x10;
+               if (tx->sta)
+                       tx->sta->tx_msdu[IEEE80211_NUM_TIDS]++;
                return TX_CONTINUE;
        }
 
@@ -831,6 +833,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
        qc = ieee80211_get_qos_ctl(hdr);
        tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
        seq = &tx->sta->tid_seq[tid];
+       tx->sta->tx_msdu[tid]++;
 
        hdr->seq_ctrl = cpu_to_le16(*seq);
 
@@ -3152,7 +3155,7 @@ int ieee80211_reserve_tid(struct ieee80211_sta *pubsta, u8 tid)
        }
 
        queues = BIT(sdata->vif.hw_queue[ieee802_1d_to_ac[tid]]);
-       __ieee80211_flush_queues(local, sdata, queues);
+       __ieee80211_flush_queues(local, sdata, queues, false);
 
        sta->reserved_tid = tid;
 
index 974ebe7..83ba6cd 100644 (file)
@@ -578,7 +578,7 @@ ieee80211_get_vif_queues(struct ieee80211_local *local,
 
 void __ieee80211_flush_queues(struct ieee80211_local *local,
                              struct ieee80211_sub_if_data *sdata,
-                             unsigned int queues)
+                             unsigned int queues, bool drop)
 {
        if (!local->ops->flush)
                return;
@@ -594,7 +594,7 @@ void __ieee80211_flush_queues(struct ieee80211_local *local,
                                        IEEE80211_QUEUE_STOP_REASON_FLUSH,
                                        false);
 
-       drv_flush(local, sdata, queues, false);
+       drv_flush(local, sdata, queues, drop);
 
        ieee80211_wake_queues_by_reason(&local->hw, queues,
                                        IEEE80211_QUEUE_STOP_REASON_FLUSH,
@@ -602,9 +602,9 @@ void __ieee80211_flush_queues(struct ieee80211_local *local,
 }
 
 void ieee80211_flush_queues(struct ieee80211_local *local,
-                           struct ieee80211_sub_if_data *sdata)
+                           struct ieee80211_sub_if_data *sdata, bool drop)
 {
-       __ieee80211_flush_queues(local, sdata, 0);
+       __ieee80211_flush_queues(local, sdata, 0, drop);
 }
 
 void ieee80211_stop_vif_queues(struct ieee80211_local *local,
@@ -1470,10 +1470,12 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_local *local,
 
        /* Check if any channel in this sband supports at least 80 MHz */
        for (i = 0; i < sband->n_channels; i++) {
-               if (!(sband->channels[i].flags & IEEE80211_CHAN_NO_80MHZ)) {
-                       have_80mhz = true;
-                       break;
-               }
+               if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED |
+                                               IEEE80211_CHAN_NO_80MHZ))
+                       continue;
+
+               have_80mhz = true;
+               break;
        }
 
        if (sband->vht_cap.vht_supported && have_80mhz) {
@@ -1735,6 +1737,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        struct cfg80211_sched_scan_request *sched_scan_req;
        bool sched_scan_stopped = false;
 
+       /* nothing to do if HW shouldn't run */
+       if (!local->open_count)
+               goto wake_up;
+
 #ifdef CONFIG_PM
        if (local->suspended)
                local->resuming = true;
@@ -1756,9 +1762,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                reconfig_due_to_wowlan = true;
        }
 #endif
-       /* everything else happens only if HW was up & running */
-       if (!local->open_count)
-               goto wake_up;
 
        /*
         * Upon resume hardware can sometimes be goofy due to
@@ -2042,7 +2045,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
         * If this is for hw restart things are still running.
         * We may want to change that later, however.
         */
-       if (!local->suspended || reconfig_due_to_wowlan)
+       if (local->open_count && (!local->suspended || reconfig_due_to_wowlan))
                drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART);
 
        if (!local->suspended)
@@ -2054,7 +2057,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        mb();
        local->resuming = false;
 
-       if (!reconfig_due_to_wowlan)
+       if (local->open_count && !reconfig_due_to_wowlan)
                drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND);
 
        list_for_each_entry(sdata, &local->interfaces, list) {
index bc9e8fc..85f9596 100644 (file)
@@ -269,51 +269,54 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
        sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
 }
 
-enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
+enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta)
 {
-       struct ieee80211_sub_if_data *sdata = sta->sdata;
-       u32 cap = sta->sta.vht_cap.cap;
-       enum ieee80211_sta_rx_bandwidth bw;
+       struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
+       u32 cap_width;
 
-       if (!sta->sta.vht_cap.vht_supported) {
-               bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
-                               IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
-               goto check_max;
-       }
+       if (!vht_cap->vht_supported)
+               return sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
+                               IEEE80211_STA_RX_BW_40 :
+                               IEEE80211_STA_RX_BW_20;
 
-       switch (sdata->vif.bss_conf.chandef.width) {
-       default:
-               WARN_ON_ONCE(1);
-               /* fall through */
+       cap_width = vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+
+       if (cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ||
+           cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)
+               return IEEE80211_STA_RX_BW_160;
+
+       return IEEE80211_STA_RX_BW_80;
+}
+
+static enum ieee80211_sta_rx_bandwidth
+ieee80211_chan_width_to_rx_bw(enum nl80211_chan_width width)
+{
+       switch (width) {
        case NL80211_CHAN_WIDTH_20_NOHT:
        case NL80211_CHAN_WIDTH_20:
-               bw = IEEE80211_STA_RX_BW_20;
-               break;
+               return IEEE80211_STA_RX_BW_20;
        case NL80211_CHAN_WIDTH_40:
-               bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
-                               IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
-               break;
+               return IEEE80211_STA_RX_BW_40;
+       case NL80211_CHAN_WIDTH_80:
+               return IEEE80211_STA_RX_BW_80;
        case NL80211_CHAN_WIDTH_160:
-               if ((cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) ==
-                               IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) {
-                       bw = IEEE80211_STA_RX_BW_160;
-                       break;
-               }
-               /* fall through */
        case NL80211_CHAN_WIDTH_80P80:
-               if ((cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) ==
-                               IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
-                       bw = IEEE80211_STA_RX_BW_160;
-                       break;
-               }
-               /* fall through */
-       case NL80211_CHAN_WIDTH_80:
-               bw = IEEE80211_STA_RX_BW_80;
+               return IEEE80211_STA_RX_BW_160;
+       default:
+               WARN_ON_ONCE(1);
+               return IEEE80211_STA_RX_BW_20;
        }
+}
+
+enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
+{
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       enum ieee80211_sta_rx_bandwidth bw;
+
+       bw = ieee80211_chan_width_to_rx_bw(sdata->vif.bss_conf.chandef.width);
+       bw = min(bw, ieee80211_sta_cap_rx_bw(sta));
+       bw = min(bw, sta->cur_max_bandwidth);
 
- check_max:
-       if (bw > sta->cur_max_bandwidth)
-               bw = sta->cur_max_bandwidth;
        return bw;
 }
 
index 53dda77..456e4c3 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/sched.h>
 #include <net/genetlink.h>
 #include <net/cfg80211.h>
+#include <net/rtnetlink.h>
 #include "nl80211.h"
 #include "core.h"
 #include "sysfs.h"
@@ -320,6 +321,20 @@ static void cfg80211_destroy_iface_wk(struct work_struct *work)
        rtnl_unlock();
 }
 
+static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
+{
+       struct cfg80211_registered_device *rdev;
+
+       rdev = container_of(work, struct cfg80211_registered_device,
+                          sched_scan_stop_wk);
+
+       rtnl_lock();
+
+       __cfg80211_stop_sched_scan(rdev, false);
+
+       rtnl_unlock();
+}
+
 /* exported functions */
 
 struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -406,6 +421,7 @@ use_default_name:
        INIT_LIST_HEAD(&rdev->destroy_list);
        spin_lock_init(&rdev->destroy_list_lock);
        INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
+       INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk);
 
 #ifdef CONFIG_CFG80211_DEFAULT_PS
        rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -560,6 +576,14 @@ int wiphy_register(struct wiphy *wiphy)
                                       BIT(NL80211_IFTYPE_MONITOR)))
                wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
 
+       if (WARN_ON((wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) &&
+                   (wiphy->regulatory_flags &
+                                       (REGULATORY_CUSTOM_REG |
+                                        REGULATORY_STRICT_REG |
+                                        REGULATORY_COUNTRY_IE_FOLLOW_POWER |
+                                        REGULATORY_COUNTRY_IE_IGNORE))))
+               return -EINVAL;
+
        if (WARN_ON(wiphy->coalesce &&
                    (!wiphy->coalesce->n_rules ||
                     !wiphy->coalesce->n_patterns) &&
@@ -778,6 +802,7 @@ void wiphy_unregister(struct wiphy *wiphy)
        flush_work(&rdev->event_work);
        cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
        flush_work(&rdev->destroy_work);
+       flush_work(&rdev->sched_scan_stop_wk);
 
 #ifdef CONFIG_PM
        if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
@@ -858,6 +883,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
                      struct wireless_dev *wdev)
 {
        struct net_device *dev = wdev->netdev;
+       struct cfg80211_sched_scan_request *sched_scan_req;
 
        ASSERT_RTNL();
        ASSERT_WDEV_LOCK(wdev);
@@ -868,7 +894,8 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
                break;
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_STATION:
-               if (rdev->sched_scan_req && dev == rdev->sched_scan_req->dev)
+               sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
+               if (sched_scan_req && dev == sched_scan_req->dev)
                        __cfg80211_stop_sched_scan(rdev, false);
 
 #ifdef CONFIG_CFG80211_WEXT
@@ -937,12 +964,17 @@ void cfg80211_stop_iface(struct wiphy *wiphy, struct wireless_dev *wdev,
 }
 EXPORT_SYMBOL(cfg80211_stop_iface);
 
+static const struct rtnl_link_ops wireless_link_ops = {
+       .kind = "wlan",
+};
+
 static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                                         unsigned long state, void *ptr)
 {
        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev;
+       struct cfg80211_sched_scan_request *sched_scan_req;
 
        if (!wdev)
                return NOTIFY_DONE;
@@ -954,6 +986,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
        switch (state) {
        case NETDEV_POST_INIT:
                SET_NETDEV_DEVTYPE(dev, &wiphy_type);
+               dev->rtnl_link_ops = &wireless_link_ops;
                break;
        case NETDEV_REGISTER:
                /*
@@ -1007,8 +1040,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                        ___cfg80211_scan_done(rdev, false);
                }
 
-               if (WARN_ON(rdev->sched_scan_req &&
-                           rdev->sched_scan_req->dev == wdev->netdev)) {
+               sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
+               if (WARN_ON(sched_scan_req &&
+                           sched_scan_req->dev == wdev->netdev)) {
                        __cfg80211_stop_sched_scan(rdev, false);
                }
 
index faa5b16..801cd49 100644 (file)
@@ -36,6 +36,13 @@ struct cfg80211_registered_device {
         * the country on the country IE changed. */
        char country_ie_alpha2[2];
 
+       /*
+        * the driver requests the regulatory core to set this regulatory
+        * domain as the wiphy's. Only used for %REGULATORY_WIPHY_SELF_MANAGED
+        * devices using the regulatory_set_wiphy_regd() API
+        */
+       const struct ieee80211_regdomain *requested_regd;
+
        /* If a Country IE has been received this tells us the environment
         * which its telling us its in. This defaults to ENVIRON_ANY */
        enum environment_cap env;
@@ -63,7 +70,7 @@ struct cfg80211_registered_device {
        u32 bss_generation;
        struct cfg80211_scan_request *scan_req; /* protected by RTNL */
        struct sk_buff *scan_msg;
-       struct cfg80211_sched_scan_request *sched_scan_req;
+       struct cfg80211_sched_scan_request __rcu *sched_scan_req;
        unsigned long suspend_at;
        struct work_struct scan_done_wk;
        struct work_struct sched_scan_results_wk;
@@ -84,6 +91,8 @@ struct cfg80211_registered_device {
        struct list_head destroy_list;
        struct work_struct destroy_work;
 
+       struct work_struct sched_scan_stop_wk;
+
        /* must be last because of the way we do wiphy_priv(),
         * and it should at least be aligned to NETDEV_ALIGN */
        struct wiphy wiphy __aligned(NETDEV_ALIGN);
index 7ca4b51..3807843 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
 };
 
@@ -396,6 +396,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
        [NL80211_ATTR_ADMITTED_TIME] = { .type = NLA_U16 },
        [NL80211_ATTR_SMPS_MODE] = { .type = NLA_U8 },
        [NL80211_ATTR_MAC_MASK] = { .len = ETH_ALEN },
+       [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -1087,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;
 
@@ -1701,6 +1707,15 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                               rdev->wiphy.max_num_csa_counters))
                        goto nla_put_failure;
 
+               if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
+                   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;
@@ -3640,8 +3655,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)
@@ -3649,7 +3664,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;
 
@@ -3661,115 +3676,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;
@@ -3788,18 +3765,62 @@ 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;
@@ -3844,7 +3865,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,
@@ -3891,7 +3912,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;
@@ -5327,42 +5349,20 @@ static int nl80211_update_mesh_config(struct sk_buff *skb,
        return err;
 }
 
-static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_put_regdom(const struct ieee80211_regdomain *regdom,
+                             struct sk_buff *msg)
 {
-       const struct ieee80211_regdomain *regdom;
-       struct sk_buff *msg;
-       void *hdr = NULL;
        struct nlattr *nl_reg_rules;
        unsigned int i;
 
-       if (!cfg80211_regdomain)
-               return -EINVAL;
-
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg)
-               return -ENOBUFS;
-
-       hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
-                            NL80211_CMD_GET_REG);
-       if (!hdr)
-               goto put_failure;
-
-       if (reg_last_request_cell_base() &&
-           nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
-                       NL80211_USER_REG_HINT_CELL_BASE))
-               goto nla_put_failure;
-
-       rcu_read_lock();
-       regdom = rcu_dereference(cfg80211_regdomain);
-
        if (nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, regdom->alpha2) ||
            (regdom->dfs_region &&
             nla_put_u8(msg, NL80211_ATTR_DFS_REGION, regdom->dfs_region)))
-               goto nla_put_failure_rcu;
+               goto nla_put_failure;
 
        nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES);
        if (!nl_reg_rules)
-               goto nla_put_failure_rcu;
+               goto nla_put_failure;
 
        for (i = 0; i < regdom->n_reg_rules; i++) {
                struct nlattr *nl_reg_rule;
@@ -5377,7 +5377,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
 
                nl_reg_rule = nla_nest_start(msg, i);
                if (!nl_reg_rule)
-                       goto nla_put_failure_rcu;
+                       goto nla_put_failure;
 
                max_bandwidth_khz = freq_range->max_bandwidth_khz;
                if (!max_bandwidth_khz)
@@ -5398,13 +5398,74 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
                                power_rule->max_eirp) ||
                    nla_put_u32(msg, NL80211_ATTR_DFS_CAC_TIME,
                                reg_rule->dfs_cac_ms))
-                       goto nla_put_failure_rcu;
+                       goto nla_put_failure;
 
                nla_nest_end(msg, nl_reg_rule);
        }
-       rcu_read_unlock();
 
        nla_nest_end(msg, nl_reg_rules);
+       return 0;
+
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
+static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
+{
+       const struct ieee80211_regdomain *regdom = NULL;
+       struct cfg80211_registered_device *rdev;
+       struct wiphy *wiphy = NULL;
+       struct sk_buff *msg;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOBUFS;
+
+       hdr = nl80211hdr_put(msg, info->snd_portid, info->snd_seq, 0,
+                            NL80211_CMD_GET_REG);
+       if (!hdr)
+               goto put_failure;
+
+       if (info->attrs[NL80211_ATTR_WIPHY]) {
+               bool self_managed;
+
+               rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
+               if (IS_ERR(rdev)) {
+                       nlmsg_free(msg);
+                       return PTR_ERR(rdev);
+               }
+
+               wiphy = &rdev->wiphy;
+               self_managed = wiphy->regulatory_flags &
+                              REGULATORY_WIPHY_SELF_MANAGED;
+               regdom = get_wiphy_regdom(wiphy);
+
+               /* a self-managed-reg device must have a private regdom */
+               if (WARN_ON(!regdom && self_managed)) {
+                       nlmsg_free(msg);
+                       return -EINVAL;
+               }
+
+               if (regdom &&
+                   nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
+                       goto nla_put_failure;
+       }
+
+       if (!wiphy && reg_last_request_cell_base() &&
+           nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
+                       NL80211_USER_REG_HINT_CELL_BASE))
+               goto nla_put_failure;
+
+       rcu_read_lock();
+
+       if (!regdom)
+               regdom = rcu_dereference(cfg80211_regdomain);
+
+       if (nl80211_put_regdom(regdom, msg))
+               goto nla_put_failure_rcu;
+
+       rcu_read_unlock();
 
        genlmsg_end(msg, hdr);
        return genlmsg_reply(msg, info);
@@ -5418,6 +5479,83 @@ put_failure:
        return -EMSGSIZE;
 }
 
+static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
+                              u32 seq, int flags, struct wiphy *wiphy,
+                              const struct ieee80211_regdomain *regdom)
+{
+       void *hdr = nl80211hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
+                                  NL80211_CMD_GET_REG);
+
+       if (!hdr)
+               return -1;
+
+       genl_dump_check_consistent(cb, hdr, &nl80211_fam);
+
+       if (nl80211_put_regdom(regdom, msg))
+               goto nla_put_failure;
+
+       if (!wiphy && reg_last_request_cell_base() &&
+           nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
+                       NL80211_USER_REG_HINT_CELL_BASE))
+               goto nla_put_failure;
+
+       if (wiphy &&
+           nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
+               goto nla_put_failure;
+
+       if (wiphy && wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
+           nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
+               goto nla_put_failure;
+
+       return genlmsg_end(msg, hdr);
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       return -EMSGSIZE;
+}
+
+static int nl80211_get_reg_dump(struct sk_buff *skb,
+                               struct netlink_callback *cb)
+{
+       const struct ieee80211_regdomain *regdom = NULL;
+       struct cfg80211_registered_device *rdev;
+       int err, reg_idx, start = cb->args[2];
+
+       rtnl_lock();
+
+       if (cfg80211_regdomain && start == 0) {
+               err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
+                                         NLM_F_MULTI, NULL,
+                                         rtnl_dereference(cfg80211_regdomain));
+               if (err < 0)
+                       goto out_err;
+       }
+
+       /* the global regdom is idx 0 */
+       reg_idx = 1;
+       list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+               regdom = get_wiphy_regdom(&rdev->wiphy);
+               if (!regdom)
+                       continue;
+
+               if (++reg_idx <= start)
+                       continue;
+
+               err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
+                                         NLM_F_MULTI, &rdev->wiphy, regdom);
+               if (err < 0) {
+                       reg_idx--;
+                       break;
+               }
+       }
+
+       cb->args[2] = reg_idx;
+       err = skb->len;
+out_err:
+       rtnl_unlock();
+       return err;
+}
+
 static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1];
@@ -6069,6 +6207,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct net_device *dev = info->user_ptr[1];
        struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_sched_scan_request *sched_scan_req;
        int err;
 
        if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
@@ -6078,27 +6217,32 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
        if (rdev->sched_scan_req)
                return -EINPROGRESS;
 
-       rdev->sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
-                                                       info->attrs);
-       err = PTR_ERR_OR_ZERO(rdev->sched_scan_req);
+       sched_scan_req = nl80211_parse_sched_scan(&rdev->wiphy, wdev,
+                                                 info->attrs);
+
+       err = PTR_ERR_OR_ZERO(sched_scan_req);
        if (err)
                goto out_err;
 
-       err = rdev_sched_scan_start(rdev, dev, rdev->sched_scan_req);
+       err = rdev_sched_scan_start(rdev, dev, sched_scan_req);
        if (err)
                goto out_free;
 
-       rdev->sched_scan_req->dev = dev;
-       rdev->sched_scan_req->wiphy = &rdev->wiphy;
+       sched_scan_req->dev = dev;
+       sched_scan_req->wiphy = &rdev->wiphy;
+
+       if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
+               sched_scan_req->owner_nlportid = info->snd_portid;
+
+       rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);
 
        nl80211_send_sched_scan(rdev, dev,
                                NL80211_CMD_START_SCHED_SCAN);
        return 0;
 
 out_free:
-       kfree(rdev->sched_scan_req);
+       kfree(sched_scan_req);
 out_err:
-       rdev->sched_scan_req = NULL;
        return err;
 }
 
@@ -6481,12 +6625,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)
@@ -6499,7 +6648,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;
 
@@ -6509,25 +6659,29 @@ 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);
@@ -6539,19 +6693,22 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
        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;
@@ -6569,13 +6726,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;
                }
@@ -6583,7 +6736,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++;
        }
@@ -8599,6 +8752,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];
@@ -8656,6 +8851,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);
        }
 
@@ -10225,7 +10425,8 @@ static const struct genl_ops nl80211_ops[] = {
        },
        {
                .cmd = NL80211_CMD_GET_REG,
-               .doit = nl80211_get_reg,
+               .doit = nl80211_get_reg_do,
+               .dumpit = nl80211_get_reg_dump,
                .policy = nl80211_policy,
                .internal_flags = NL80211_FLAG_NEED_RTNL,
                /* can be retrieved by unprivileged users */
@@ -10939,25 +11140,9 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
                                NL80211_MCGRP_SCAN, GFP_KERNEL);
 }
 
-/*
- * This can happen on global regulatory changes or device specific settings
- * based on custom world regulatory domains.
- */
-void nl80211_send_reg_change_event(struct regulatory_request *request)
+static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
+                                         struct regulatory_request *request)
 {
-       struct sk_buff *msg;
-       void *hdr;
-
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg)
-               return;
-
-       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE);
-       if (!hdr) {
-               nlmsg_free(msg);
-               return;
-       }
-
        /* Userspace can always count this one always being set */
        if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
                goto nla_put_failure;
@@ -10983,8 +11168,46 @@ void nl80211_send_reg_change_event(struct regulatory_request *request)
                        goto nla_put_failure;
        }
 
-       if (request->wiphy_idx != WIPHY_IDX_INVALID &&
-           nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
+       if (request->wiphy_idx != WIPHY_IDX_INVALID) {
+               struct wiphy *wiphy = wiphy_idx_to_wiphy(request->wiphy_idx);
+
+               if (wiphy &&
+                   nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
+                       goto nla_put_failure;
+
+               if (wiphy &&
+                   wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
+                   nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
+                       goto nla_put_failure;
+       }
+
+       return true;
+
+nla_put_failure:
+       return false;
+}
+
+/*
+ * This can happen on global regulatory changes or device specific settings
+ * based on custom regulatory domains.
+ */
+void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
+                                    struct regulatory_request *request)
+{
+       struct sk_buff *msg;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, cmd_id);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       if (nl80211_reg_change_event_fill(msg, request) == false)
                goto nla_put_failure;
 
        genlmsg_end(msg, hdr);
@@ -11523,7 +11746,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;
@@ -11534,12 +11757,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);
 
@@ -11547,27 +11774,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)) {
                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,
@@ -12471,6 +12687,13 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 
        list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
                bool schedule_destroy_work = false;
+               bool schedule_scan_stop = false;
+               struct cfg80211_sched_scan_request *sched_scan_req =
+                       rcu_dereference(rdev->sched_scan_req);
+
+               if (sched_scan_req && notify->portid &&
+                   sched_scan_req->owner_nlportid == notify->portid)
+                       schedule_scan_stop = true;
 
                list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) {
                        cfg80211_mlme_unregister_socket(wdev, notify->portid);
@@ -12501,6 +12724,12 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
                                spin_unlock(&rdev->destroy_list_lock);
                                schedule_work(&rdev->destroy_work);
                        }
+               } else if (schedule_scan_stop) {
+                       sched_scan_req->owner_nlportid = 0;
+
+                       if (rdev->ops->sched_scan_stop &&
+                           rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
+                               schedule_work(&rdev->sched_scan_stop_wk);
                }
        }
 
index 7ad70d6..84d4edf 100644 (file)
@@ -17,7 +17,21 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
                             struct net_device *netdev, u32 cmd);
 void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
                                     struct net_device *netdev);
-void nl80211_send_reg_change_event(struct regulatory_request *request);
+void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
+                                    struct regulatory_request *request);
+
+static inline void
+nl80211_send_reg_change_event(struct regulatory_request *request)
+{
+       nl80211_common_reg_change_event(NL80211_CMD_REG_CHANGE, request);
+}
+
+static inline void
+nl80211_send_wiphy_reg_change_event(struct regulatory_request *request)
+{
+       nl80211_common_reg_change_event(NL80211_CMD_WIPHY_REG_CHANGE, request);
+}
+
 void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
                          struct net_device *netdev,
                          const u8 *buf, size_t len, gfp_t gfp);
index 7b83098..886cc7c 100644 (file)
@@ -109,7 +109,7 @@ static struct regulatory_request core_request_world = {
  * protected by RTNL (and can be accessed with RCU protection)
  */
 static struct regulatory_request __rcu *last_request =
-       (void __rcu *)&core_request_world;
+       (void __force __rcu *)&core_request_world;
 
 /* To trigger userspace events */
 static struct platform_device *reg_pdev;
@@ -142,7 +142,7 @@ static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
        return rtnl_dereference(cfg80211_regdomain);
 }
 
-static const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy)
+const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy)
 {
        return rtnl_dereference(wiphy->regd);
 }
@@ -1307,6 +1307,9 @@ static bool ignore_reg_update(struct wiphy *wiphy,
 {
        struct regulatory_request *lr = get_last_request();
 
+       if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+               return true;
+
        if (!lr) {
                REG_DBG_PRINT("Ignoring regulatory request set by %s "
                              "since last_request is not set\n",
@@ -1683,8 +1686,12 @@ static void handle_channel_custom(struct wiphy *wiphy,
        if (IS_ERR(reg_rule)) {
                REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",
                              chan->center_freq);
-               chan->orig_flags |= IEEE80211_CHAN_DISABLED;
-               chan->flags = chan->orig_flags;
+               if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
+                       chan->flags |= IEEE80211_CHAN_DISABLED;
+               } else {
+                       chan->orig_flags |= IEEE80211_CHAN_DISABLED;
+                       chan->flags = chan->orig_flags;
+               }
                return;
        }
 
@@ -1709,7 +1716,13 @@ static void handle_channel_custom(struct wiphy *wiphy,
        chan->dfs_state = NL80211_DFS_USABLE;
 
        chan->beacon_found = false;
-       chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
+
+       if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+               chan->flags = chan->orig_flags | bw_flags |
+                             map_regdom_flags(reg_rule->flags);
+       else
+               chan->flags |= map_regdom_flags(reg_rule->flags) | bw_flags;
+
        chan->max_antenna_gain = (int) MBI_TO_DBI(power_rule->max_antenna_gain);
        chan->max_reg_power = chan->max_power =
                (int) MBM_TO_DBM(power_rule->max_eirp);
@@ -2095,6 +2108,26 @@ out_free:
        reg_free_request(reg_request);
 }
 
+static bool reg_only_self_managed_wiphys(void)
+{
+       struct cfg80211_registered_device *rdev;
+       struct wiphy *wiphy;
+       bool self_managed_found = false;
+
+       ASSERT_RTNL();
+
+       list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+               wiphy = &rdev->wiphy;
+               if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+                       self_managed_found = true;
+               else
+                       return false;
+       }
+
+       /* make sure at least one self-managed wiphy exists */
+       return self_managed_found;
+}
+
 /*
  * Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_*
  * Regulatory hints come on a first come first serve basis and we
@@ -2126,6 +2159,11 @@ static void reg_process_pending_hints(void)
 
        spin_unlock(&reg_requests_lock);
 
+       if (reg_only_self_managed_wiphys()) {
+               reg_free_request(reg_request);
+               return;
+       }
+
        reg_process_hint(reg_request);
 }
 
@@ -2153,11 +2191,52 @@ static void reg_process_pending_beacon_hints(void)
        spin_unlock_bh(&reg_pending_beacons_lock);
 }
 
+static void reg_process_self_managed_hints(void)
+{
+       struct cfg80211_registered_device *rdev;
+       struct wiphy *wiphy;
+       const struct ieee80211_regdomain *tmp;
+       const struct ieee80211_regdomain *regd;
+       enum ieee80211_band band;
+       struct regulatory_request request = {};
+
+       list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+               wiphy = &rdev->wiphy;
+
+               spin_lock(&reg_requests_lock);
+               regd = rdev->requested_regd;
+               rdev->requested_regd = NULL;
+               spin_unlock(&reg_requests_lock);
+
+               if (regd == NULL)
+                       continue;
+
+               tmp = get_wiphy_regdom(wiphy);
+               rcu_assign_pointer(wiphy->regd, regd);
+               rcu_free_regdom(tmp);
+
+               for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+                       handle_band_custom(wiphy, wiphy->bands[band], regd);
+
+               reg_process_ht_flags(wiphy);
+
+               request.wiphy_idx = get_wiphy_idx(wiphy);
+               request.alpha2[0] = regd->alpha2[0];
+               request.alpha2[1] = regd->alpha2[1];
+               request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
+
+               nl80211_send_wiphy_reg_change_event(&request);
+       }
+
+       reg_check_channels();
+}
+
 static void reg_todo(struct work_struct *work)
 {
        rtnl_lock();
        reg_process_pending_hints();
        reg_process_pending_beacon_hints();
+       reg_process_self_managed_hints();
        rtnl_unlock();
 }
 
@@ -2438,6 +2517,8 @@ static void restore_regulatory_settings(bool reset_user)
        world_alpha2[1] = cfg80211_world_regdom->alpha2[1];
 
        list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+               if (rdev->wiphy.regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+                       continue;
                if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG)
                        restore_custom_reg_settings(&rdev->wiphy);
        }
@@ -2841,10 +2922,79 @@ int set_regdom(const struct ieee80211_regdomain *rd)
        return 0;
 }
 
+static int __regulatory_set_wiphy_regd(struct wiphy *wiphy,
+                                      struct ieee80211_regdomain *rd)
+{
+       const struct ieee80211_regdomain *regd;
+       const struct ieee80211_regdomain *prev_regd;
+       struct cfg80211_registered_device *rdev;
+
+       if (WARN_ON(!wiphy || !rd))
+               return -EINVAL;
+
+       if (WARN(!(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED),
+                "wiphy should have REGULATORY_WIPHY_SELF_MANAGED\n"))
+               return -EPERM;
+
+       if (WARN(!is_valid_rd(rd), "Invalid regulatory domain detected\n")) {
+               print_regdomain_info(rd);
+               return -EINVAL;
+       }
+
+       regd = reg_copy_regd(rd);
+       if (IS_ERR(regd))
+               return PTR_ERR(regd);
+
+       rdev = wiphy_to_rdev(wiphy);
+
+       spin_lock(&reg_requests_lock);
+       prev_regd = rdev->requested_regd;
+       rdev->requested_regd = regd;
+       spin_unlock(&reg_requests_lock);
+
+       kfree(prev_regd);
+       return 0;
+}
+
+int regulatory_set_wiphy_regd(struct wiphy *wiphy,
+                             struct ieee80211_regdomain *rd)
+{
+       int ret = __regulatory_set_wiphy_regd(wiphy, rd);
+
+       if (ret)
+               return ret;
+
+       schedule_work(&reg_work);
+       return 0;
+}
+EXPORT_SYMBOL(regulatory_set_wiphy_regd);
+
+int regulatory_set_wiphy_regd_sync_rtnl(struct wiphy *wiphy,
+                                       struct ieee80211_regdomain *rd)
+{
+       int ret;
+
+       ASSERT_RTNL();
+
+       ret = __regulatory_set_wiphy_regd(wiphy, rd);
+       if (ret)
+               return ret;
+
+       /* process the request immediately */
+       reg_process_self_managed_hints();
+       return 0;
+}
+EXPORT_SYMBOL(regulatory_set_wiphy_regd_sync_rtnl);
+
 void wiphy_regulatory_register(struct wiphy *wiphy)
 {
        struct regulatory_request *lr;
 
+       /* self-managed devices ignore external hints */
+       if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+               wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS |
+                                          REGULATORY_COUNTRY_IE_IGNORE;
+
        if (!reg_dev_ignore_cell_hint(wiphy))
                reg_num_devs_support_basehint++;
 
index 5e48031..4b45d6e 100644 (file)
@@ -38,6 +38,7 @@ unsigned int reg_get_max_bandwidth(const struct ieee80211_regdomain *rd,
                                   const struct ieee80211_reg_rule *rule);
 
 bool reg_last_request_cell_base(void);
+const struct ieee80211_regdomain *get_wiphy_regdom(struct wiphy *wiphy);
 
 /**
  * regulatory_hint_found_beacon - hints a beacon was found on a channel
index bda39f1..c705c3e 100644 (file)
@@ -257,7 +257,7 @@ void __cfg80211_sched_scan_results(struct work_struct *wk)
 
        rtnl_lock();
 
-       request = rdev->sched_scan_req;
+       request = rtnl_dereference(rdev->sched_scan_req);
 
        /* we don't have sched_scan_req anymore if the scan is stopping */
        if (request) {
@@ -279,7 +279,8 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy)
 {
        trace_cfg80211_sched_scan_results(wiphy);
        /* ignore if we're not scanning */
-       if (wiphy_to_rdev(wiphy)->sched_scan_req)
+
+       if (rcu_access_pointer(wiphy_to_rdev(wiphy)->sched_scan_req))
                queue_work(cfg80211_wq,
                           &wiphy_to_rdev(wiphy)->sched_scan_results_wk);
 }
@@ -308,6 +309,7 @@ EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
 int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
                               bool driver_initiated)
 {
+       struct cfg80211_sched_scan_request *sched_scan_req;
        struct net_device *dev;
 
        ASSERT_RTNL();
@@ -315,7 +317,8 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
        if (!rdev->sched_scan_req)
                return -ENOENT;
 
-       dev = rdev->sched_scan_req->dev;
+       sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
+       dev = sched_scan_req->dev;
 
        if (!driver_initiated) {
                int err = rdev_sched_scan_stop(rdev, dev);
@@ -325,8 +328,8 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
 
        nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
 
-       kfree(rdev->sched_scan_req);
-       rdev->sched_scan_req = NULL;
+       RCU_INIT_POINTER(rdev->sched_scan_req, NULL);
+       kfree_rcu(sched_scan_req, rcu_head);
 
        return 0;
 }
index ad38910..b17b369 100644 (file)
@@ -1604,11 +1604,12 @@ TRACE_EVENT(rdev_return_int_survey_info,
                WIPHY_ENTRY
                CHAN_ENTRY
                __field(int, ret)
-               __field(u64, channel_time)
-               __field(u64, channel_time_busy)
-               __field(u64, channel_time_ext_busy)
-               __field(u64, channel_time_rx)
-               __field(u64, channel_time_tx)
+               __field(u64, time)
+               __field(u64, time_busy)
+               __field(u64, time_ext_busy)
+               __field(u64, time_rx)
+               __field(u64, time_tx)
+               __field(u64, time_scan)
                __field(u32, filled)
                __field(s8, noise)
        ),
@@ -1616,22 +1617,24 @@ TRACE_EVENT(rdev_return_int_survey_info,
                WIPHY_ASSIGN;
                CHAN_ASSIGN(info->channel);
                __entry->ret = ret;
-               __entry->channel_time = info->channel_time;
-               __entry->channel_time_busy = info->channel_time_busy;
-               __entry->channel_time_ext_busy = info->channel_time_ext_busy;
-               __entry->channel_time_rx = info->channel_time_rx;
-               __entry->channel_time_tx = info->channel_time_tx;
+               __entry->time = info->time;
+               __entry->time_busy = info->time_busy;
+               __entry->time_ext_busy = info->time_ext_busy;
+               __entry->time_rx = info->time_rx;
+               __entry->time_tx = info->time_tx;
+               __entry->time_scan = info->time_scan;
                __entry->filled = info->filled;
                __entry->noise = info->noise;
        ),
        TP_printk(WIPHY_PR_FMT ", returned: %d, " CHAN_PR_FMT
                  ", channel time: %llu, channel time busy: %llu, "
                  "channel time extension busy: %llu, channel time rx: %llu, "
-                 "channel time tx: %llu, filled: %u, noise: %d",
+                 "channel time tx: %llu, scan time: %llu, filled: %u, noise: %d",
                  WIPHY_PR_ARG, __entry->ret, CHAN_PR_ARG,
-                 __entry->channel_time, __entry->channel_time_busy,
-                 __entry->channel_time_ext_busy, __entry->channel_time_rx,
-                 __entry->channel_time_tx, __entry->filled, __entry->noise)
+                 __entry->time, __entry->time_busy,
+                 __entry->time_ext_busy, __entry->time_rx,
+                 __entry->time_tx, __entry->time_scan,
+                 __entry->filled, __entry->noise)
 );
 
 TRACE_EVENT(rdev_tdls_oper,
index 0f47948..5b24d39 100644 (file)
@@ -1300,7 +1300,7 @@ static int cfg80211_wext_giwrate(struct net_device *dev,
        if (err)
                return err;
 
-       if (!(sinfo.filled & STATION_INFO_TX_BITRATE))
+       if (!(sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)))
                return -EOPNOTSUPP;
 
        rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate);
@@ -1340,7 +1340,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
 
        switch (rdev->wiphy.signal_type) {
        case CFG80211_SIGNAL_TYPE_MBM:
-               if (sinfo.filled & STATION_INFO_SIGNAL) {
+               if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL)) {
                        int sig = sinfo.signal;
                        wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
                        wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
@@ -1354,7 +1354,7 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
                        break;
                }
        case CFG80211_SIGNAL_TYPE_UNSPEC:
-               if (sinfo.filled & STATION_INFO_SIGNAL) {
+               if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL)) {
                        wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
                        wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
                        wstats.qual.level = sinfo.signal;
@@ -1367,9 +1367,9 @@ static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
        }
 
        wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
-       if (sinfo.filled & STATION_INFO_RX_DROP_MISC)
+       if (sinfo.filled & BIT(NL80211_STA_INFO_RX_DROP_MISC))
                wstats.discard.misc = sinfo.rx_dropped_misc;
-       if (sinfo.filled & STATION_INFO_TX_FAILED)
+       if (sinfo.filled & BIT(NL80211_STA_INFO_TX_FAILED))
                wstats.discard.retries = sinfo.tx_failed;
 
        return &wstats;