]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
Merge tag 'mac80211-next-for-davem-2015-10-05' of git://git.kernel.org/pub/scm/linux...
authorDavid S. Miller <davem@davemloft.net>
Wed, 7 Oct 2015 11:29:18 +0000 (04:29 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 7 Oct 2015 11:29:18 +0000 (04:29 -0700)
Johannes Berg says:

====================
For the current cycle, we have the following right now:
 * many internal fixes, API improvements, cleanups, etc.
 * full AP client state tracking in cfg80211/mac80211 from Ayala
 * VHT support (in mac80211) for mesh
 * some A-MSDU in A-MPDU support from Emmanuel
 * show current TX power to userspace (from RafaƂ)
 * support for netlink dump in vendor commands (myself)
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
1  2 
drivers/net/wireless/mac80211_hwsim.c
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/mlme.c
net/mac80211/rate.c
net/mac80211/tdls.c
net/wireless/reg.c

index 66c963dbc3fd26427043a6aefe817a1938d89a9e,2af2f3d0cc3197090d7433583415dc7d939fa46a..ee46f4647fbc4803d629047462b4f696fcfea2f6
@@@ -1819,7 -1819,7 +1819,7 @@@ static int mac80211_hwsim_ampdu_action(
                                       struct ieee80211_vif *vif,
                                       enum ieee80211_ampdu_mlme_action action,
                                       struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                                      u8 buf_size)
+                                      u8 buf_size, bool amsdu)
  {
        switch (action) {
        case IEEE80211_AMPDU_TX_START:
@@@ -2190,8 -2190,9 +2190,8 @@@ static void hwsim_mcast_config_msg(stru
                                   struct genl_info *info)
  {
        if (info)
 -              genl_notify(&hwsim_genl_family, mcast_skb,
 -                          genl_info_net(info), info->snd_portid,
 -                          HWSIM_MCGRP_CONFIG, info->nlhdr, GFP_KERNEL);
 +              genl_notify(&hwsim_genl_family, mcast_skb, info,
 +                          HWSIM_MCGRP_CONFIG, GFP_KERNEL);
        else
                genlmsg_multicast(&hwsim_genl_family, mcast_skb, 0,
                                  HWSIM_MCGRP_CONFIG, GFP_KERNEL);
diff --combined include/net/mac80211.h
index bfc569498bfa793013766e6e16158d29bb84c9ef,301fceb2fd1001ed35da89124c3d5637986718e2..4ec6fedeb22041c65848b4df9a34960a9006f25c
@@@ -5,6 -5,7 +5,7 @@@
   * Copyright 2006-2007        Jiri Benc <jbenc@suse.cz>
   * Copyright 2007-2010        Johannes Berg <johannes@sipsolutions.net>
   * Copyright 2013-2014  Intel Mobile Communications GmbH
+  * Copyright (C) 2015 Intel Deutschland GmbH
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
@@@ -477,9 -478,7 +478,9 @@@ struct ieee80211_event 
   * @chandef: Channel definition for this BSS -- the hardware might be
   *    configured a higher bandwidth than this BSS uses, for example.
   * @ht_operation_mode: HT operation mode like in &struct ieee80211_ht_operation.
 - *    This field is only valid when the channel type is one of the HT types.
 + *    This field is only valid when the channel is a wide HT/VHT channel.
 + *    Note that with TDLS this can be the case (channel is HT, protection must
 + *    be used from this field) even when the BSS association isn't using HT.
   * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
   *    implies disabled
   * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
@@@ -1360,6 -1359,8 +1361,8 @@@ enum ieee80211_vif_flags 
   * @debugfs_dir: debugfs dentry, can be used by drivers to create own per
   *    interface debug files. Note that it will be NULL for the virtual
   *    monitor interface (if that is requested.)
+  * @probe_req_reg: probe requests should be reported to mac80211 for this
+  *    interface.
   * @drv_priv: data area for driver use, will always be aligned to
   *    sizeof(void *).
   * @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
@@@ -1384,6 -1385,8 +1387,8 @@@ struct ieee80211_vif 
        struct dentry *debugfs_dir;
  #endif
  
+       unsigned int probe_req_reg;
        /* must be last */
        u8 drv_priv[0] __aligned(sizeof(void *));
  };
@@@ -1494,10 -1497,8 +1499,8 @@@ enum ieee80211_key_flags 
   *    - Temporal Authenticator Rx MIC Key (64 bits)
   * @icv_len: The ICV length for this key type
   * @iv_len: The IV length for this key type
-  * @drv_priv: pointer for driver use
   */
  struct ieee80211_key_conf {
-       void *drv_priv;
        atomic64_t tx_pn;
        u32 cipher;
        u8 icv_len;
@@@ -1894,6 -1895,12 +1897,12 @@@ struct ieee80211_txq 
   * @IEEE80211_HW_TDLS_WIDER_BW: The device/driver supports wider bandwidth
   *    than then BSS bandwidth for a TDLS link on the base channel.
   *
+  * @IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU: The driver supports receiving A-MSDUs
+  *    within A-MPDU.
+  *
+  * @IEEE80211_HW_BEACON_TX_STATUS: The device/driver provides TX status
+  *    for sent beacons.
+  *
   * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
   */
  enum ieee80211_hw_flags {
        IEEE80211_HW_SUPPORTS_CLONED_SKBS,
        IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS,
        IEEE80211_HW_TDLS_WIDER_BW,
+       IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU,
+       IEEE80211_HW_BEACON_TX_STATUS,
  
        /* keep last, obviously */
        NUM_IEEE80211_HW_FLAGS
@@@ -2827,6 -2836,13 +2838,13 @@@ enum ieee80211_reconfig_type 
   *    See the section "Frame filtering" for more information.
   *    This callback must be implemented and can sleep.
   *
+  * @config_iface_filter: Configure the interface's RX filter.
+  *    This callback is optional and is used to configure which frames
+  *    should be passed to mac80211. The filter_flags is the combination
+  *    of FIF_* flags. The changed_flags is a bit mask that indicates
+  *    which flags are changed.
+  *    This callback can sleep.
+  *
   * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit
   *    must be set or cleared for a given STA. Must be atomic.
   *
   *    buffer size of 8. Correct ways to retransmit #1 would be:
   *     - TX:       1 or 18 or 81
   *    Even "189" would be wrong since 1 could be lost again.
+  *    The @amsdu parameter is valid when the action is set to
+  *    %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's ability
+  *    to receive A-MSDU within A-MPDU.
   *
   *    Returns a negative error code on failure.
   *    The callback can sleep.
@@@ -3266,6 -3285,10 +3287,10 @@@ struct ieee80211_ops 
                                 unsigned int changed_flags,
                                 unsigned int *total_flags,
                                 u64 multicast);
+       void (*config_iface_filter)(struct ieee80211_hw *hw,
+                                   struct ieee80211_vif *vif,
+                                   unsigned int filter_flags,
+                                   unsigned int changed_flags);
        int (*set_tim)(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
                       bool set);
        int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                            struct ieee80211_vif *vif,
                            enum ieee80211_ampdu_mlme_action action,
                            struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                           u8 buf_size);
+                           u8 buf_size, bool amsdu);
        int (*get_survey)(struct ieee80211_hw *hw, int idx,
                struct survey_info *survey);
        void (*rfkill_poll)(struct ieee80211_hw *hw);
diff --combined net/mac80211/cfg.c
index 7a77a1470f25bd26aa280eada69479da1f4e9dd9,1b91fcd0aa112b56ad22ed0baa401e5354451801..68e551e263c6bcf19e7641f034c2087fcc428d0b
@@@ -981,7 -981,7 +981,7 @@@ static int sta_apply_auth_flags(struct 
                 * well. Some drivers require rate control initialized
                 * before drv_sta_state() is called.
                 */
-               if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+               if (!test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
                        rate_control_rate_init(sta);
  
                ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
@@@ -1120,8 -1120,11 +1120,11 @@@ static int sta_apply_parameters(struct 
            local->hw.queues >= IEEE80211_NUM_ACS)
                sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME);
  
-       /* auth flags will be set later for TDLS stations */
-       if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+       /* auth flags will be set later for TDLS,
+        * and for unassociated stations that move to assocaited */
+       if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+           !((mask & BIT(NL80211_STA_FLAG_ASSOCIATED)) &&
+             (set & BIT(NL80211_STA_FLAG_ASSOCIATED)))) {
                ret = sta_apply_auth_flags(local, sta, mask, set);
                if (ret)
                        return ret;
                set_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH);
  
        if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+           !sdata->u.mgd.tdls_wider_bw_prohibited &&
            ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) &&
            params->ext_capab_len >= 8 &&
            params->ext_capab[7] & WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED)
                sta_apply_mesh_params(local, sta, params);
  
        /* set the STA state after all sta info from usermode has been set */
-       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) ||
+           set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
                ret = sta_apply_auth_flags(local, sta, mask, set);
                if (ret)
                        return ret;
@@@ -1254,12 -1259,14 +1259,14 @@@ static int ieee80211_add_station(struc
         * defaults -- if userspace wants something else we'll
         * change it accordingly in sta_apply_parameters()
         */
-       if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) {
+       if (!(params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) &&
+           !(params->sta_flags_set & (BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                                       BIT(NL80211_STA_FLAG_ASSOCIATED)))) {
                sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
                sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
-       } else {
-               sta->sta.tdls = true;
        }
+       if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
+               sta->sta.tdls = true;
  
        err = sta_apply_parameters(local, sta, params);
        if (err) {
        }
  
        /*
-        * for TDLS, rate control should be initialized only when
-        * rates are known and station is marked authorized
+        * for TDLS and for unassociated station, rate control should be
+        * initialized only when rates are known and station is marked
+        * authorized/associated
         */
-       if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+       if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
+           test_sta_flag(sta, WLAN_STA_ASSOC))
                rate_control_rate_init(sta);
  
        layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
@@@ -1346,7 -1355,10 +1355,10 @@@ static int ieee80211_change_station(str
                break;
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_AP_VLAN:
-               statype = CFG80211_STA_AP_CLIENT;
+               if (test_sta_flag(sta, WLAN_STA_ASSOC))
+                       statype = CFG80211_STA_AP_CLIENT;
+               else
+                       statype = CFG80211_STA_AP_CLIENT_UNASSOC;
                break;
        default:
                err = -EOPNOTSUPP;
@@@ -2468,13 -2480,8 +2480,13 @@@ static int ieee80211_set_cqm_rssi_confi
            rssi_hyst == bss_conf->cqm_rssi_hyst)
                return 0;
  
 +      if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER &&
 +          !(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI))
 +              return -EOPNOTSUPP;
 +
        bss_conf->cqm_rssi_thold = rssi_thold;
        bss_conf->cqm_rssi_hyst = rssi_hyst;
 +      sdata->u.mgd.last_cqm_event_signal = 0;
  
        /* tell the driver upon association, unless already associated */
        if (sdata->u.mgd.associated &&
@@@ -2519,17 -2526,15 +2531,17 @@@ static int ieee80211_set_bitrate_mask(s
                        continue;
  
                for (j = 0; j < IEEE80211_HT_MCS_MASK_LEN; j++) {
 -                      if (~sdata->rc_rateidx_mcs_mask[i][j])
 +                      if (~sdata->rc_rateidx_mcs_mask[i][j]) {
                                sdata->rc_has_mcs_mask[i] = true;
 +                              break;
 +                      }
 +              }
  
 -                      if (~sdata->rc_rateidx_vht_mcs_mask[i][j])
 +              for (j = 0; j < NL80211_VHT_NSS_MAX; j++) {
 +                      if (~sdata->rc_rateidx_vht_mcs_mask[i][j]) {
                                sdata->rc_has_vht_mcs_mask[i] = true;
 -
 -                      if (sdata->rc_has_mcs_mask[i] &&
 -                          sdata->rc_has_vht_mcs_mask[i])
                                break;
 +                      }
                }
        }
  
@@@ -3522,18 -3527,32 +3534,32 @@@ static void ieee80211_mgmt_frame_regist
                                          u16 frame_type, bool reg)
  {
        struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
  
        switch (frame_type) {
        case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ:
-               if (reg)
+               if (reg) {
                        local->probe_req_reg++;
-               else
-                       local->probe_req_reg--;
+                       sdata->vif.probe_req_reg++;
+               } else {
+                       if (local->probe_req_reg)
+                               local->probe_req_reg--;
+                       if (sdata->vif.probe_req_reg)
+                               sdata->vif.probe_req_reg--;
+               }
  
                if (!local->open_count)
                        break;
  
-               ieee80211_queue_work(&local->hw, &local->reconfig_filter);
+               if (sdata->vif.probe_req_reg == 1)
+                       drv_config_iface_filter(local, sdata, FIF_PROBE_REQ,
+                                               FIF_PROBE_REQ);
+               else if (sdata->vif.probe_req_reg == 0)
+                       drv_config_iface_filter(local, sdata, 0,
+                                               FIF_PROBE_REQ);
+               ieee80211_configure_filter(local);
                break;
        default:
                break;
diff --combined net/mac80211/mlme.c
index cd7e55e08a238c23f546ce7d6860759345eff371,88047bf6c0e0d21bf730220d3169ab5db8d25a6f..56ef9a8e151c72d46e64e7f325e00fdf8c46253a
@@@ -81,13 -81,6 +81,6 @@@ MODULE_PARM_DESC(probe_wait_ms
                 "Maximum time(ms) to wait for probe response"
                 " before disconnecting (reason 4).");
  
- /*
-  * Weight given to the latest Beacon frame when calculating average signal
-  * strength for Beacon frames received in the current BSS. This must be
-  * between 1 and 15.
-  */
- #define IEEE80211_SIGNAL_AVE_WEIGHT   3
  /*
   * How many Beacon frames need to have been used in average signal strength
   * before starting to indicate signal change events.
@@@ -943,7 -936,7 +936,7 @@@ void ieee80211_send_pspoll(struct ieee8
  
  void ieee80211_send_nullfunc(struct ieee80211_local *local,
                             struct ieee80211_sub_if_data *sdata,
-                            int powersave)
+                            bool powersave)
  {
        struct sk_buff *skb;
        struct ieee80211_hdr_3addr *nullfunc;
@@@ -1427,7 -1420,7 +1420,7 @@@ static void ieee80211_enable_ps(struct 
                          msecs_to_jiffies(conf->dynamic_ps_timeout));
        } else {
                if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK))
-                       ieee80211_send_nullfunc(local, sdata, 1);
+                       ieee80211_send_nullfunc(local, sdata, true);
  
                if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
                    ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
@@@ -1642,7 -1635,7 +1635,7 @@@ void ieee80211_dynamic_ps_enable_work(s
                                  msecs_to_jiffies(
                                  local->hw.conf.dynamic_ps_timeout));
                } else {
-                       ieee80211_send_nullfunc(local, sdata, 1);
+                       ieee80211_send_nullfunc(local, sdata, true);
                        /* Flush to get the tx status of nullfunc frame */
                        ieee80211_flush_queues(local, sdata, false);
                }
@@@ -2275,7 -2268,7 +2268,7 @@@ static void ieee80211_mgd_probe_ap_send
  
        if (ieee80211_hw_check(&sdata->local->hw, REPORTS_TX_ACK_STATUS)) {
                ifmgd->nullfunc_failed = false;
-               ieee80211_send_nullfunc(sdata->local, sdata, 0);
+               ieee80211_send_nullfunc(sdata->local, sdata, false);
        } else {
                int ssid_len;
  
@@@ -3262,16 -3255,6 +3255,6 @@@ static void ieee80211_rx_mgmt_probe_res
        if (ifmgd->associated &&
            ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
                ieee80211_reset_ap_probe(sdata);
-       if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies &&
-           ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) {
-               /* got probe response, continue with auth */
-               sdata_info(sdata, "direct probe responded\n");
-               ifmgd->auth_data->tries = 0;
-               ifmgd->auth_data->timeout = jiffies;
-               ifmgd->auth_data->timeout_started = true;
-               run_again(sdata, ifmgd->auth_data->timeout);
-       }
  }
  
  /*
@@@ -3374,24 -3357,21 +3357,21 @@@ static void ieee80211_rx_mgmt_beacon(st
        bssid = ifmgd->associated->bssid;
  
        /* Track average RSSI from the Beacon frames of the current AP */
-       ifmgd->last_beacon_signal = rx_status->signal;
        if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
                ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
-               ifmgd->ave_beacon_signal = rx_status->signal * 16;
+               ewma_beacon_signal_init(&ifmgd->ave_beacon_signal);
                ifmgd->last_cqm_event_signal = 0;
                ifmgd->count_beacon_signal = 1;
                ifmgd->last_ave_beacon_signal = 0;
        } else {
-               ifmgd->ave_beacon_signal =
-                       (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
-                        (16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
-                        ifmgd->ave_beacon_signal) / 16;
                ifmgd->count_beacon_signal++;
        }
  
+       ewma_beacon_signal_add(&ifmgd->ave_beacon_signal, -rx_status->signal);
        if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold &&
            ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
-               int sig = ifmgd->ave_beacon_signal;
+               int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
                int last_sig = ifmgd->last_ave_beacon_signal;
                struct ieee80211_event event = {
                        .type = RSSI_EVENT,
        if (bss_conf->cqm_rssi_thold &&
            ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
            !(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) {
-               int sig = ifmgd->ave_beacon_signal / 16;
+               int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
                int last_event = ifmgd->last_cqm_event_signal;
                int thold = bss_conf->cqm_rssi_thold;
                int hyst = bss_conf->cqm_rssi_hyst;
                if (sig < thold &&
                    (last_event == 0 || sig < last_event - hyst)) {
                        ifmgd->last_cqm_event_signal = sig;
                                          len - baselen, false, &elems,
                                          care_about_ies, ncrc);
  
-       if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK)) {
-               bool directed_tim = ieee80211_check_tim(elems.tim,
-                                                       elems.tim_len,
-                                                       ifmgd->aid);
-               if (directed_tim) {
-                       if (local->hw.conf.dynamic_ps_timeout > 0) {
-                               if (local->hw.conf.flags & IEEE80211_CONF_PS) {
-                                       local->hw.conf.flags &= ~IEEE80211_CONF_PS;
-                                       ieee80211_hw_config(local,
-                                                           IEEE80211_CONF_CHANGE_PS);
-                               }
-                               ieee80211_send_nullfunc(local, sdata, 0);
-                       } else if (!local->pspolling && sdata->u.mgd.powersave) {
-                               local->pspolling = true;
-                               /*
-                                * Here is assumed that the driver will be
-                                * able to send ps-poll frame and receive a
-                                * response even though power save mode is
-                                * enabled, but some drivers might require
-                                * to disable power save here. This needs
-                                * to be investigated.
-                                */
-                               ieee80211_send_pspoll(local, sdata);
+       if (ieee80211_hw_check(&local->hw, PS_NULLFUNC_STACK) &&
+           ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid)) {
+               if (local->hw.conf.dynamic_ps_timeout > 0) {
+                       if (local->hw.conf.flags & IEEE80211_CONF_PS) {
+                               local->hw.conf.flags &= ~IEEE80211_CONF_PS;
+                               ieee80211_hw_config(local,
+                                                   IEEE80211_CONF_CHANGE_PS);
                        }
+                       ieee80211_send_nullfunc(local, sdata, false);
+               } else if (!local->pspolling && sdata->u.mgd.powersave) {
+                       local->pspolling = true;
+                       /*
+                        * Here is assumed that the driver will be
+                        * able to send ps-poll frame and receive a
+                        * response even though power save mode is
+                        * enabled, but some drivers might require
+                        * to disable power save here. This needs
+                        * to be investigated.
+                        */
+                       ieee80211_send_pspoll(local, sdata);
                }
        }
  
@@@ -3717,12 -3694,14 +3694,14 @@@ static void ieee80211_sta_connection_lo
                                    reason);
  }
  
- static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
+ static int ieee80211_auth(struct ieee80211_sub_if_data *sdata)
  {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_mgd_auth_data *auth_data = ifmgd->auth_data;
        u32 tx_flags = 0;
+       u16 trans = 1;
+       u16 status = 0;
  
        sdata_assert_lock(sdata);
  
  
        drv_mgd_prepare_tx(local, sdata);
  
-       if (auth_data->bss->proberesp_ies) {
-               u16 trans = 1;
-               u16 status = 0;
-               sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
-                          auth_data->bss->bssid, auth_data->tries,
-                          IEEE80211_AUTH_MAX_TRIES);
+       sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
+                  auth_data->bss->bssid, auth_data->tries,
+                  IEEE80211_AUTH_MAX_TRIES);
  
-               auth_data->expected_transaction = 2;
+       auth_data->expected_transaction = 2;
  
-               if (auth_data->algorithm == WLAN_AUTH_SAE) {
-                       trans = auth_data->sae_trans;
-                       status = auth_data->sae_status;
-                       auth_data->expected_transaction = trans;
-               }
-               if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
-                       tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
-                                  IEEE80211_TX_INTFL_MLME_CONN_TX;
-               ieee80211_send_auth(sdata, trans, auth_data->algorithm, status,
-                                   auth_data->data, auth_data->data_len,
-                                   auth_data->bss->bssid,
-                                   auth_data->bss->bssid, NULL, 0, 0,
-                                   tx_flags);
-       } else {
-               const u8 *ssidie;
+       if (auth_data->algorithm == WLAN_AUTH_SAE) {
+               trans = auth_data->sae_trans;
+               status = auth_data->sae_status;
+               auth_data->expected_transaction = trans;
+       }
  
-               sdata_info(sdata, "direct probe to %pM (try %d/%i)\n",
-                          auth_data->bss->bssid, auth_data->tries,
-                          IEEE80211_AUTH_MAX_TRIES);
+       if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
+               tx_flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
+                          IEEE80211_TX_INTFL_MLME_CONN_TX;
  
-               rcu_read_lock();
-               ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID);
-               if (!ssidie) {
-                       rcu_read_unlock();
-                       return -EINVAL;
-               }
-               /*
-                * Direct probe is sent to broadcast address as some APs
-                * will not answer to direct packet in unassociated state.
-                */
-               ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL,
-                                        ssidie + 2, ssidie[1],
-                                        NULL, 0, (u32) -1, true, 0,
-                                        auth_data->bss->channel, false);
-               rcu_read_unlock();
-       }
+       ieee80211_send_auth(sdata, trans, auth_data->algorithm, status,
+                           auth_data->data, auth_data->data_len,
+                           auth_data->bss->bssid,
+                           auth_data->bss->bssid, NULL, 0, 0,
+                           tx_flags);
  
        if (tx_flags == 0) {
                auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
@@@ -3874,8 -3826,7 +3826,7 @@@ void ieee80211_sta_work(struct ieee8021
                bool status_acked = ifmgd->status_acked;
  
                ifmgd->status_received = false;
-               if (ifmgd->auth_data &&
-                   (ieee80211_is_probe_req(fc) || ieee80211_is_auth(fc))) {
+               if (ifmgd->auth_data && ieee80211_is_auth(fc)) {
                        if (status_acked) {
                                ifmgd->auth_data->timeout =
                                        jiffies + IEEE80211_AUTH_TIMEOUT_SHORT;
                         * so let's just kill the auth data
                         */
                        ieee80211_destroy_auth_data(sdata, false);
-               } else if (ieee80211_probe_auth(sdata)) {
+               } else if (ieee80211_auth(sdata)) {
                        u8 bssid[ETH_ALEN];
                        struct ieee80211_event event = {
                                .type = MLME_EVENT,
@@@ -4267,8 -4218,6 +4218,8 @@@ static int ieee80211_prep_channel(struc
        struct ieee80211_supported_band *sband;
        struct cfg80211_chan_def chandef;
        int ret;
 +      u32 i;
 +      bool have_80mhz;
  
        sband = local->hw.wiphy->bands[cbss->channel->band];
  
                }
        }
  
 +      /* Allow VHT if at least one channel on the sband supports 80 MHz */
 +      have_80mhz = false;
 +      for (i = 0; i < sband->n_channels; i++) {
 +              if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED |
 +                                              IEEE80211_CHAN_NO_80MHZ))
 +                      continue;
 +
 +              have_80mhz = true;
 +              break;
 +      }
 +
 +      if (!have_80mhz)
 +              ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
 +
        ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
                                                     cbss->channel,
                                                     ht_cap, ht_oper, vht_oper,
@@@ -4613,7 -4548,7 +4564,7 @@@ int ieee80211_mgd_auth(struct ieee80211
        if (err)
                goto err_clear;
  
-       err = ieee80211_probe_auth(sdata);
+       err = ieee80211_auth(sdata);
        if (err) {
                sta_info_destroy_addr(sdata, req->bss->bssid);
                goto err_clear;
diff --combined net/mac80211/rate.c
index 9ce8883d5f449ed438f0a4a4a4807ede153c6725,48d053b0085804d77e826d2705e767a08e517472..b07e2f748f9388f0e7f591555aced4856200292f
@@@ -305,7 -305,10 +305,10 @@@ static void __rate_control_send_low(str
                info->control.rates[0].idx = i;
                break;
        }
-       WARN_ON_ONCE(i == sband->n_bitrates);
+       WARN_ONCE(i == sband->n_bitrates,
+                 "no supported rates (0x%x) in rate_mask 0x%x with flags 0x%x\n",
+                 sta ? sta->supp_rates[sband->band] : 0,
+                 rate_mask, rate_flags);
  
        info->control.rates[0].count =
                (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
@@@ -716,7 -719,7 +719,7 @@@ static bool rate_control_cap_mask(struc
  
                /* Filter out rates that the STA does not support */
                *mask &= sta->supp_rates[sband->band];
 -              for (i = 0; i < sizeof(mcs_mask); i++)
 +              for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++)
                        mcs_mask[i] &= sta->ht_cap.mcs.rx_mask[i];
  
                sta_vht_cap = sta->vht_cap.vht_mcs.rx_mcs_map;
diff --combined net/mac80211/tdls.c
index 4e202d0679b26a0dfa0b89c5ae189f2ce7b56883,52f3187f90ba7d5d577e637b423bf2f2a63cb01e..ecc5e2a8f80b62445e77d0c9d9c0fc816db29667
@@@ -41,9 -41,11 +41,11 @@@ static void ieee80211_tdls_add_ext_capa
                                         struct sk_buff *skb)
  {
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        bool chan_switch = local->hw.wiphy->features &
                           NL80211_FEATURE_TDLS_CHANNEL_SWITCH;
-       bool wider_band = ieee80211_hw_check(&local->hw, TDLS_WIDER_BW);
+       bool wider_band = ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) &&
+                         !ifmgd->tdls_wider_bw_prohibited;
        enum ieee80211_band band = ieee80211_get_sdata_band(sdata);
        struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
        bool vht = sband && sband->vht_cap.vht_supported;
@@@ -331,8 -333,8 +333,8 @@@ ieee80211_tdls_chandef_vht_upgrade(stru
  
        /* proceed to downgrade the chandef until usable or the same */
        while (uc.width > max_width &&
-              !cfg80211_reg_can_beacon(sdata->local->hw.wiphy,
-                                       &uc, sdata->wdev.iftype))
+              !cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &uc,
+                                             sdata->wdev.iftype))
                ieee80211_chandef_downgrade(&uc);
  
        if (!cfg80211_chandef_identical(&uc, &sta->tdls_chandef)) {
@@@ -1249,58 -1251,6 +1251,58 @@@ static void iee80211_tdls_recalc_chanct
        mutex_unlock(&local->chanctx_mtx);
  }
  
 +static int iee80211_tdls_have_ht_peers(struct ieee80211_sub_if_data *sdata)
 +{
 +      struct sta_info *sta;
 +      bool result = false;
 +
 +      rcu_read_lock();
 +      list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
 +              if (!sta->sta.tdls || sta->sdata != sdata || !sta->uploaded ||
 +                  !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
 +                  !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH) ||
 +                  !sta->sta.ht_cap.ht_supported)
 +                      continue;
 +              result = true;
 +              break;
 +      }
 +      rcu_read_unlock();
 +
 +      return result;
 +}
 +
 +static void
 +iee80211_tdls_recalc_ht_protection(struct ieee80211_sub_if_data *sdata,
 +                                 struct sta_info *sta)
 +{
 +      struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 +      bool tdls_ht;
 +      u16 protection = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED |
 +                       IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
 +                       IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT;
 +      u16 opmode;
 +
 +      /* Nothing to do if the BSS connection uses HT */
 +      if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
 +              return;
 +
 +      tdls_ht = (sta && sta->sta.ht_cap.ht_supported) ||
 +                iee80211_tdls_have_ht_peers(sdata);
 +
 +      opmode = sdata->vif.bss_conf.ht_operation_mode;
 +
 +      if (tdls_ht)
 +              opmode |= protection;
 +      else
 +              opmode &= ~protection;
 +
 +      if (opmode == sdata->vif.bss_conf.ht_operation_mode)
 +              return;
 +
 +      sdata->vif.bss_conf.ht_operation_mode = opmode;
 +      ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
 +}
 +
  int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
                        const u8 *peer, enum nl80211_tdls_operation oper)
  {
                return -ENOTSUPP;
        }
  
 +      /* protect possible bss_conf changes and avoid concurrency in
 +       * ieee80211_bss_info_change_notify()
 +       */
 +      sdata_lock(sdata);
        mutex_lock(&local->mtx);
        tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
  
  
                iee80211_tdls_recalc_chanctx(sdata);
  
 -              rcu_read_lock();
 +              mutex_lock(&local->sta_mtx);
                sta = sta_info_get(sdata, peer);
                if (!sta) {
 -                      rcu_read_unlock();
 +                      mutex_unlock(&local->sta_mtx);
                        ret = -ENOLINK;
                        break;
                }
  
 +              iee80211_tdls_recalc_ht_protection(sdata, sta);
 +
                set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
 -              rcu_read_unlock();
 +              mutex_unlock(&local->sta_mtx);
  
                WARN_ON_ONCE(is_zero_ether_addr(sdata->u.mgd.tdls_peer) ||
                             !ether_addr_equal(sdata->u.mgd.tdls_peer, peer));
                ieee80211_flush_queues(local, sdata, false);
  
                ret = sta_info_destroy_addr(sdata, peer);
 +
 +              mutex_lock(&local->sta_mtx);
 +              iee80211_tdls_recalc_ht_protection(sdata, NULL);
 +              mutex_unlock(&local->sta_mtx);
 +
                iee80211_tdls_recalc_chanctx(sdata);
                break;
        default:
                                     &sdata->u.mgd.request_smps_work);
  
        mutex_unlock(&local->mtx);
 +      sdata_unlock(sdata);
        return ret;
  }
  
diff --combined net/wireless/reg.c
index 2510b231451ec8c7e0f0f33d523739dce3387ca3,70aef72c4ca2111c8b864a09eea0f0aa6e7c4055..7258246b7458713eb14230c906246e230972b1b4
@@@ -1040,8 -1040,8 +1040,8 @@@ freq_reg_info_regd(struct wiphy *wiphy
        return ERR_PTR(-EINVAL);
  }
  
- const struct ieee80211_reg_rule *__freq_reg_info(struct wiphy *wiphy,
                                               u32 center_freq, u32 min_bw)
+ static const struct ieee80211_reg_rule *
__freq_reg_info(struct wiphy *wiphy, u32 center_freq, u32 min_bw)
  {
        const struct ieee80211_regdomain *regd = reg_get_regdomain(wiphy);
        const struct ieee80211_reg_rule *reg_rule = NULL;
@@@ -2625,7 -2625,7 +2625,7 @@@ static void restore_regulatory_settings
         * settings, user regulatory settings takes precedence.
         */
        if (is_an_alpha2(alpha2))
 -              regulatory_hint_user(user_alpha2, NL80211_USER_REG_HINT_USER);
 +              regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER);
  
        spin_lock(&reg_requests_lock);
        list_splice_tail_init(&tmp_reg_req_list, &reg_requests_list);