Merge tag 'mac80211-next-for-davem-2015-03-30' of git://git.kernel.org/pub/scm/linux...
authorDavid S. Miller <davem@davemloft.net>
Tue, 31 Mar 2015 20:39:04 +0000 (16:39 -0400)
committerDavid S. Miller <davem@davemloft.net>
Tue, 31 Mar 2015 20:39:04 +0000 (16:39 -0400)
Johannes Berg says:

====================
Lots of updates for net-next; along with the usual flurry
of small fixes, cleanups and internal features we have:
 * VHT support for TDLS and IBSS (conditional on drivers though)
 * first TX performance improvements (the biggest will come later)
 * many suspend/resume (race) fixes
 * name_assign_type support from Tom Gundersen
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
26 files changed:
1  2 
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/wil6210/cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/cw1200/sta.c
drivers/net/wireless/iwlwifi/mvm/coex.c
drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
include/net/cfg80211.h
net/mac80211/cfg.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/mesh.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/tx.c
net/mac80211/util.c
net/wireless/ibss.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/trace.h

@@@ -611,7 -611,7 +611,7 @@@ static int ath10k_monitor_vdev_start(st
  
        ret = ath10k_vdev_setup_sync(ar);
        if (ret) {
 -              ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i: %d\n",
 +              ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i start: %d\n",
                            vdev_id, ret);
                return ret;
        }
@@@ -658,7 -658,7 +658,7 @@@ static int ath10k_monitor_vdev_stop(str
  
        ret = ath10k_vdev_setup_sync(ar);
        if (ret)
 -              ath10k_warn(ar, "failed to synchronise monitor vdev %i: %d\n",
 +              ath10k_warn(ar, "failed to synchronize monitor vdev %i stop: %d\n",
                            ar->monitor_vdev_id, ret);
  
        ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
@@@ -927,9 -927,8 +927,9 @@@ static int ath10k_vdev_start_restart(st
  
        ret = ath10k_vdev_setup_sync(ar);
        if (ret) {
 -              ath10k_warn(ar, "failed to synchronise setup for vdev %i: %d\n",
 -                          arg.vdev_id, ret);
 +              ath10k_warn(ar,
 +                          "failed to synchronize setup for vdev %i restart %d: %d\n",
 +                          arg.vdev_id, restart, ret);
                return ret;
        }
  
@@@ -967,7 -966,7 +967,7 @@@ static int ath10k_vdev_stop(struct ath1
  
        ret = ath10k_vdev_setup_sync(ar);
        if (ret) {
 -              ath10k_warn(ar, "failed to syncronise setup for vdev %i: %d\n",
 +              ath10k_warn(ar, "failed to synchronize setup for vdev %i stop: %d\n",
                            arvif->vdev_id, ret);
                return ret;
        }
@@@ -1183,7 -1182,7 +1183,7 @@@ static void ath10k_control_ibss(struct 
                if (is_zero_ether_addr(arvif->bssid))
                        return;
  
 -              memset(arvif->bssid, 0, ETH_ALEN);
 +              eth_zero_addr(arvif->bssid);
  
                return;
        }
@@@ -1254,20 -1253,6 +1254,20 @@@ static int ath10k_mac_vif_recalc_ps_pol
        return 0;
  }
  
 +static int ath10k_mac_ps_vif_count(struct ath10k *ar)
 +{
 +      struct ath10k_vif *arvif;
 +      int num = 0;
 +
 +      lockdep_assert_held(&ar->conf_mutex);
 +
 +      list_for_each_entry(arvif, &ar->arvifs, list)
 +              if (arvif->ps)
 +                      num++;
 +
 +      return num;
 +}
 +
  static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
  {
        struct ath10k *ar = arvif->ar;
        enum wmi_sta_ps_mode psmode;
        int ret;
        int ps_timeout;
 +      bool enable_ps;
  
        lockdep_assert_held(&arvif->ar->conf_mutex);
  
        if (arvif->vif->type != NL80211_IFTYPE_STATION)
                return 0;
  
 -      if (vif->bss_conf.ps) {
 +      enable_ps = arvif->ps;
 +
 +      if (enable_ps && ath10k_mac_ps_vif_count(ar) > 1 &&
 +          !test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT,
 +                    ar->fw_features)) {
 +              ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n",
 +                          arvif->vdev_id);
 +              enable_ps = false;
 +      }
 +
 +      if (enable_ps) {
                psmode = WMI_STA_PS_MODE_ENABLED;
                param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
  
@@@ -1412,7 -1386,8 +1412,8 @@@ static void ath10k_peer_assoc_h_crypto(
        lockdep_assert_held(&ar->conf_mutex);
  
        bss = cfg80211_get_bss(ar->hw->wiphy, ar->hw->conf.chandef.chan,
-                              info->bssid, NULL, 0, 0, 0);
+                              info->bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY,
+                              IEEE80211_PRIVACY_ANY);
        if (bss) {
                const struct cfg80211_bss_ies *ies;
  
@@@ -1807,68 -1782,6 +1808,68 @@@ static int ath10k_setup_peer_smps(struc
                                         ath10k_smps_map[smps]);
  }
  
 +static int ath10k_mac_vif_recalc_txbf(struct ath10k *ar,
 +                                    struct ieee80211_vif *vif,
 +                                    struct ieee80211_sta_vht_cap vht_cap)
 +{
 +      struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 +      int ret;
 +      u32 param;
 +      u32 value;
 +
 +      if (!(ar->vht_cap_info &
 +            (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
 +             IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
 +             IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
 +             IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)))
 +              return 0;
 +
 +      param = ar->wmi.vdev_param->txbf;
 +      value = 0;
 +
 +      if (WARN_ON(param == WMI_VDEV_PARAM_UNSUPPORTED))
 +              return 0;
 +
 +      /* The following logic is correct. If a remote STA advertises support
 +       * for being a beamformer then we should enable us being a beamformee.
 +       */
 +
 +      if (ar->vht_cap_info &
 +          (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
 +           IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
 +              if (vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
 +                      value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE;
 +
 +              if (vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
 +                      value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE;
 +      }
 +
 +      if (ar->vht_cap_info &
 +          (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
 +           IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
 +              if (vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)
 +                      value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER;
 +
 +              if (vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)
 +                      value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER;
 +      }
 +
 +      if (value & WMI_VDEV_PARAM_TXBF_MU_TX_BFEE)
 +              value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE;
 +
 +      if (value & WMI_VDEV_PARAM_TXBF_MU_TX_BFER)
 +              value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER;
 +
 +      ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, value);
 +      if (ret) {
 +              ath10k_warn(ar, "failed to submit vdev param txbf 0x%x: %d\n",
 +                          value, ret);
 +              return ret;
 +      }
 +
 +      return 0;
 +}
 +
  /* can be called only in mac80211 callbacks due to `key_count` usage */
  static void ath10k_bss_assoc(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif,
        struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        struct ieee80211_sta_ht_cap ht_cap;
 +      struct ieee80211_sta_vht_cap vht_cap;
        struct wmi_peer_assoc_complete_arg peer_arg;
        struct ieee80211_sta *ap_sta;
        int ret;
        /* ap_sta must be accessed only within rcu section which must be left
         * before calling ath10k_setup_peer_smps() which might sleep. */
        ht_cap = ap_sta->ht_cap;
 +      vht_cap = ap_sta->vht_cap;
  
        ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg);
        if (ret) {
                return;
        }
  
 +      ret = ath10k_mac_vif_recalc_txbf(ar, vif, vht_cap);
 +      if (ret) {
 +              ath10k_warn(ar, "failed to recalc txbf for vdev %i on bss %pM: %d\n",
 +                          arvif->vdev_id, bss_conf->bssid, ret);
 +              return;
 +      }
 +
        ath10k_dbg(ar, ATH10K_DBG_MAC,
                   "mac vdev %d up (associated) bssid %pM aid %d\n",
                   arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
        }
  
        arvif->is_up = true;
 +
 +      /* Workaround: Some firmware revisions (tested with qca6174
 +       * WLAN.RM.2.0-00073) have buggy powersave state machine and must be
 +       * poked with peer param command.
 +       */
 +      ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, arvif->bssid,
 +                                      WMI_PEER_DUMMY_VAR, 1);
 +      if (ret) {
 +              ath10k_warn(ar, "failed to poke peer %pM param for ps workaround on vdev %i: %d\n",
 +                          arvif->bssid, arvif->vdev_id, ret);
 +              return;
 +      }
  }
  
  static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
  {
        struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
 +      struct ieee80211_sta_vht_cap vht_cap = {};
        int ret;
  
        lockdep_assert_held(&ar->conf_mutex);
  
        arvif->def_wep_key_idx = -1;
  
 +      ret = ath10k_mac_vif_recalc_txbf(ar, vif, vht_cap);
 +      if (ret) {
 +              ath10k_warn(ar, "failed to recalc txbf for vdev %i: %d\n",
 +                          arvif->vdev_id, ret);
 +              return;
 +      }
 +
        arvif->is_up = false;
  }
  
@@@ -2671,17 -2555,6 +2672,17 @@@ static int ath10k_start_scan(struct ath
                return -ETIMEDOUT;
        }
  
 +      /* If we failed to start the scan, return error code at
 +       * this point.  This is probably due to some issue in the
 +       * firmware, but no need to wedge the driver due to that...
 +       */
 +      spin_lock_bh(&ar->data_lock);
 +      if (ar->scan.state == ATH10K_SCAN_IDLE) {
 +              spin_unlock_bh(&ar->data_lock);
 +              return -EINVAL;
 +      }
 +      spin_unlock_bh(&ar->data_lock);
 +
        /* Add a 200ms margin to account for event/command processing */
        ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
                                     msecs_to_jiffies(arg->max_scan_time+200));
@@@ -3451,10 -3324,9 +3452,10 @@@ static void ath10k_remove_interface(str
        list_del(&arvif->list);
  
        if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
 -              ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr);
 +              ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id,
 +                                           vif->addr);
                if (ret)
 -                      ath10k_warn(ar, "failed to remove peer for AP vdev %i: %d\n",
 +                      ath10k_warn(ar, "failed to submit AP self-peer removal on vdev %i: %d\n",
                                    arvif->vdev_id, ret);
  
                kfree(arvif->u.ap.noa_data);
                ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n",
                            arvif->vdev_id, ret);
  
 +      /* Some firmware revisions don't notify host about self-peer removal
 +       * until after associated vdev is deleted.
 +       */
 +      if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
 +              ret = ath10k_wait_for_peer_deleted(ar, arvif->vdev_id,
 +                                                 vif->addr);
 +              if (ret)
 +                      ath10k_warn(ar, "failed to remove AP self-peer on vdev %i: %d\n",
 +                                  arvif->vdev_id, ret);
 +
 +              spin_lock_bh(&ar->data_lock);
 +              ar->num_peers--;
 +              spin_unlock_bh(&ar->data_lock);
 +      }
 +
        ath10k_peer_cleanup(ar, arvif->vdev_id);
  
        mutex_unlock(&ar->conf_mutex);
@@@ -3678,9 -3535,7 +3679,9 @@@ static void ath10k_bss_info_changed(str
        }
  
        if (changed & BSS_CHANGED_PS) {
 -              ret = ath10k_mac_vif_setup_ps(arvif);
 +              arvif->ps = vif->bss_conf.ps;
 +
 +              ret = ath10k_config_ps(ar);
                if (ret)
                        ath10k_warn(ar, "failed to setup ps on vdev %i: %d\n",
                                    arvif->vdev_id, ret);
@@@ -686,20 -686,21 +686,21 @@@ ath6kl_add_bss_if_needed(struct ath6kl_
  {
        struct ath6kl *ar = vif->ar;
        struct cfg80211_bss *bss;
-       u16 cap_mask, cap_val;
+       u16 cap_val;
+       enum ieee80211_bss_type bss_type;
        u8 *ie;
  
        if (nw_type & ADHOC_NETWORK) {
-               cap_mask = WLAN_CAPABILITY_IBSS;
                cap_val = WLAN_CAPABILITY_IBSS;
+               bss_type = IEEE80211_BSS_TYPE_IBSS;
        } else {
-               cap_mask = WLAN_CAPABILITY_ESS;
                cap_val = WLAN_CAPABILITY_ESS;
+               bss_type = IEEE80211_BSS_TYPE_ESS;
        }
  
        bss = cfg80211_get_bss(ar->wiphy, chan, bssid,
                               vif->ssid, vif->ssid_len,
-                              cap_mask, cap_val);
+                              bss_type, IEEE80211_PRIVACY_ANY);
        if (bss == NULL) {
                /*
                 * Since cfg80211 may not yet know about the BSS,
@@@ -1495,6 -1496,7 +1496,7 @@@ static int ath6kl_cfg80211_set_power_mg
  
  static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy,
                                                      const char *name,
+                                                     unsigned char name_assign_type,
                                                      enum nl80211_iftype type,
                                                      u32 *flags,
                                                      struct vif_params *params)
                return ERR_PTR(-EINVAL);
        }
  
-       wdev = ath6kl_interface_add(ar, name, type, if_idx, nw_type);
+       wdev = ath6kl_interface_add(ar, name, name_assign_type, type, if_idx, nw_type);
        if (!wdev)
                return ERR_PTR(-ENOMEM);
  
@@@ -2033,7 -2035,7 +2035,7 @@@ static int ath6kl_wow_sta(struct ath6k
        int ret;
  
        /* Setup unicast pkt pattern */
 -      memset(mac_mask, 0xff, ETH_ALEN);
 +      eth_broadcast_addr(mac_mask);
        ret = ath6kl_wmi_add_wow_pattern_cmd(ar->wmi,
                                vif->fw_vif_idx, WOW_LIST_ID,
                                ETH_ALEN, 0, ndev->dev_addr,
@@@ -3633,13 -3635,14 +3635,14 @@@ void ath6kl_cfg80211_vif_cleanup(struc
  }
  
  struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
+                                         unsigned char name_assign_type,
                                          enum nl80211_iftype type,
                                          u8 fw_vif_idx, u8 nw_type)
  {
        struct net_device *ndev;
        struct ath6kl_vif *vif;
  
-       ndev = alloc_netdev(sizeof(*vif), name, NET_NAME_UNKNOWN, ether_setup);
+       ndev = alloc_netdev(sizeof(*vif), name, name_assign_type, ether_setup);
        if (!ndev)
                return NULL;
  
@@@ -387,29 -387,15 +387,29 @@@ static int wil_cfg80211_connect(struct 
        int ch;
        int rc = 0;
  
 +      wil_print_connect_params(wil, sme);
 +
        if (test_bit(wil_status_fwconnecting, wil->status) ||
            test_bit(wil_status_fwconnected, wil->status))
                return -EALREADY;
  
 -      wil_print_connect_params(wil, sme);
 +      if (sme->ie_len > WMI_MAX_IE_LEN) {
 +              wil_err(wil, "IE too large (%td bytes)\n", sme->ie_len);
 +              return -ERANGE;
 +      }
 +
 +      rsn_eid = sme->ie ?
 +                      cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
 +                      NULL;
 +
 +      if (sme->privacy && !rsn_eid) {
 +              wil_err(wil, "Missing RSN IE for secure connection\n");
 +              return -EINVAL;
 +      }
  
        bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
                               sme->ssid, sme->ssid_len,
-                              WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
+                              IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
        if (!bss) {
                wil_err(wil, "Unable to find BSS\n");
                return -ENOENT;
                rc = -ENOENT;
                goto out;
        }
 +      wil->privacy = sme->privacy;
  
 -      rsn_eid = sme->ie ?
 -                      cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
 -                      NULL;
 -      if (rsn_eid) {
 -              if (sme->ie_len > WMI_MAX_IE_LEN) {
 -                      rc = -ERANGE;
 -                      wil_err(wil, "IE too large (%td bytes)\n",
 -                              sme->ie_len);
 -                      goto out;
 -              }
 +      if (wil->privacy) {
                /* For secure assoc, send WMI_DELETE_CIPHER_KEY_CMD */
                rc = wmi_del_cipher_key(wil, 0, bss->bssid);
                if (rc) {
                        bss->capability);
                goto out;
        }
 -      if (rsn_eid) {
 +      if (wil->privacy) {
                conn.dot11_auth_mode = WMI_AUTH11_SHARED;
                conn.auth_mode = WMI_AUTH_WPA2_PSK;
                conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
@@@ -775,7 -769,7 +775,7 @@@ static int wil_cfg80211_start_ap(struc
        wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
                   bcon->assocresp_ies);
  
 -      wil->secure_pcp = info->privacy;
 +      wil->privacy = info->privacy;
  
        netif_carrier_on(ndev);
  
@@@ -625,6 -625,7 +625,7 @@@ static bool brcmf_is_ibssmode(struct br
  
  static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
                                                     const char *name,
+                                                    unsigned char name_assign_type,
                                                     enum nl80211_iftype type,
                                                     u32 *flags,
                                                     struct vif_params *params)
        case NL80211_IFTYPE_P2P_CLIENT:
        case NL80211_IFTYPE_P2P_GO:
        case NL80211_IFTYPE_P2P_DEVICE:
-               wdev = brcmf_p2p_add_vif(wiphy, name, type, flags, params);
+               wdev = brcmf_p2p_add_vif(wiphy, name, name_assign_type, type, flags, params);
                if (!IS_ERR(wdev))
                        brcmf_cfg80211_update_proto_addr_mode(wdev);
                return wdev;
@@@ -700,7 -701,7 +701,7 @@@ s32 brcmf_notify_escan_complete(struct 
                /* Do a scan abort to stop the driver's scan engine */
                brcmf_dbg(SCAN, "ABORT scan in firmware\n");
                memset(&params_le, 0, sizeof(params_le));
 -              memset(params_le.bssid, 0xFF, ETH_ALEN);
 +              eth_broadcast_addr(params_le.bssid);
                params_le.bss_type = DOT11_BSSTYPE_ANY;
                params_le.scan_type = 0;
                params_le.channel_num = cpu_to_le32(1);
@@@ -866,7 -867,7 +867,7 @@@ static void brcmf_escan_prep(struct brc
        char *ptr;
        struct brcmf_ssid_le ssid_le;
  
 -      memset(params_le->bssid, 0xFF, ETH_ALEN);
 +      eth_broadcast_addr(params_le->bssid);
        params_le->bss_type = DOT11_BSSTYPE_ANY;
        params_le->scan_type = 0;
        params_le->channel_num = 0;
@@@ -1050,6 -1051,10 +1051,6 @@@ brcmf_cfg80211_escan(struct wiphy *wiph
        if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif)
                vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif;
  
 -      /* Arm scan timeout timer */
 -      mod_timer(&cfg->escan_timeout, jiffies +
 -                      WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
 -
        escan_req = false;
        if (request) {
                /* scan bss */
                }
        }
  
 +      /* Arm scan timeout timer */
 +      mod_timer(&cfg->escan_timeout, jiffies +
 +                      WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
 +
        return 0;
  
  scan_out:
        clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
 -      if (timer_pending(&cfg->escan_timeout))
 -              del_timer_sync(&cfg->escan_timeout);
        cfg->scan_request = NULL;
        return err;
  }
@@@ -1373,8 -1376,8 +1374,8 @@@ brcmf_cfg80211_join_ibss(struct wiphy *
                                   BRCMF_ASSOC_PARAMS_FIXED_SIZE;
                memcpy(profile->bssid, params->bssid, ETH_ALEN);
        } else {
 -              memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
 -              memset(profile->bssid, 0, ETH_ALEN);
 +              eth_broadcast_addr(join_params.params_le.bssid);
 +              eth_zero_addr(profile->bssid);
        }
  
        /* Channel */
@@@ -1848,7 -1851,7 +1849,7 @@@ brcmf_cfg80211_connect(struct wiphy *wi
        if (sme->bssid)
                memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN);
        else
 -              memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN);
 +              eth_broadcast_addr(ext_join_params->assoc_le.bssid);
  
        if (cfg->channel) {
                ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1);
        if (sme->bssid)
                memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN);
        else
 -              memset(join_params.params_le.bssid, 0xFF, ETH_ALEN);
 +              eth_broadcast_addr(join_params.params_le.bssid);
  
        if (cfg->channel) {
                join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec);
@@@ -2250,6 -2253,7 +2251,6 @@@ brcmf_cfg80211_del_key(struct wiphy *wi
  
        if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
                /* we ignore this key index in this case */
 -              brcmf_err("invalid key index (%d)\n", key_idx);
                return -EINVAL;
        }
  
@@@ -4269,7 -4273,7 +4270,7 @@@ brcmf_cfg80211_del_station(struct wiph
                return -EIO;
  
        memcpy(&scbval.ea, params->mac, ETH_ALEN);
 -      scbval.val = cpu_to_le32(WLAN_REASON_DEAUTH_LEAVING);
 +      scbval.val = cpu_to_le32(params->reason_code);
        err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON,
                                     &scbval, sizeof(scbval));
        if (err)
@@@ -697,7 -697,7 +697,7 @@@ static s32 brcmf_p2p_escan(struct brcmf
        else
                sparams->scan_type = 1;
  
 -      memset(&sparams->bssid, 0xFF, ETH_ALEN);
 +      eth_broadcast_addr(sparams->bssid);
        if (ssid.SSID_len)
                memcpy(sparams->ssid_le.SSID, ssid.SSID, ssid.SSID_len);
        sparams->ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
@@@ -2246,11 -2246,13 +2246,13 @@@ static void brcmf_p2p_delete_p2pdev(str
   *
   * @wiphy: wiphy device of new interface.
   * @name: name of the new interface.
+  * @name_assign_type: origin of the interface name
   * @type: nl80211 interface type.
   * @flags: not used.
   * @params: contains mac address for P2P device.
   */
  struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
+                                      unsigned char name_assign_type,
                                       enum nl80211_iftype type, u32 *flags,
                                       struct vif_params *params)
  {
        }
  
        strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1);
+       ifp->ndev->name_assign_type = name_assign_type;
        err = brcmf_net_attach(ifp, true);
        if (err) {
                brcmf_err("Registering netdevice failed\n");
@@@ -293,7 -293,7 +293,7 @@@ void cw1200_remove_interface(struct iee
        }
        priv->vif = NULL;
        priv->mode = NL80211_IFTYPE_MONITOR;
 -      memset(priv->mac_addr, 0, ETH_ALEN);
 +      eth_zero_addr(priv->mac_addr);
        memset(&priv->p2p_ps_modeinfo, 0, sizeof(priv->p2p_ps_modeinfo));
        cw1200_free_keys(priv);
        cw1200_setup_mac(priv);
@@@ -1240,8 -1240,8 +1240,8 @@@ static void cw1200_do_join(struct cw120
  
        bssid = priv->vif->bss_conf.bssid;
  
-       bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel,
-                       bssid, NULL, 0, 0, 0);
+       bss = cfg80211_get_bss(priv->hw->wiphy, priv->channel, bssid, NULL, 0,
+                              IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
  
        if (!bss && !conf->ibss_joined) {
                wsm_unlock_tx(priv);
@@@ -611,7 -611,7 +611,7 @@@ int iwl_send_bt_init_conf(struct iwl_mv
                bt_cmd->enabled_modules |=
                        cpu_to_le32(BT_COEX_SYNC2SCO_ENABLED);
  
 -      if (IWL_MVM_BT_COEX_CORUNNING)
 +      if (iwl_mvm_bt_is_plcr_supported(mvm))
                bt_cmd->enabled_modules |= cpu_to_le32(BT_COEX_CORUN_ENABLED);
  
        if (IWL_MVM_BT_COEX_MPLUT) {
@@@ -793,8 -793,7 +793,8 @@@ static void iwl_mvm_bt_notif_iterator(v
        if (!vif->bss_conf.assoc)
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
  
 -      if (IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
 +      if (mvmvif->phy_ctxt &&
 +          IWL_COEX_IS_RRC_ON(mvm->last_bt_notif.ttc_rrc_status,
                               mvmvif->phy_ctxt->id))
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
  
@@@ -1024,7 -1023,7 +1024,7 @@@ static void iwl_mvm_bt_rssi_iterator(vo
  }
  
  void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                          enum ieee80211_rssi_event rssi_event)
+                          enum ieee80211_rssi_event_data rssi_event)
  {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_bt_iterator_data data = {
@@@ -1235,7 -1234,7 +1235,7 @@@ int iwl_mvm_rx_ant_coupling_notif(struc
        if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BT_COEX_SPLIT))
                return iwl_mvm_rx_ant_coupling_notif_old(mvm, rxb, dev_cmd);
  
 -      if (!IWL_MVM_BT_COEX_CORUNNING)
 +      if (!iwl_mvm_bt_is_plcr_supported(mvm))
                return 0;
  
        lockdep_assert_held(&mvm->mutex);
@@@ -619,7 -619,7 +619,7 @@@ int iwl_send_bt_init_conf_old(struct iw
        if (IWL_MVM_BT_COEX_SYNC2SCO)
                bt_cmd->flags |= cpu_to_le32(BT_COEX_SYNC2SCO);
  
 -      if (IWL_MVM_BT_COEX_CORUNNING) {
 +      if (iwl_mvm_bt_is_plcr_supported(mvm)) {
                bt_cmd->valid_bit_msk |= cpu_to_le32(BT_VALID_CORUN_LUT_20 |
                                                     BT_VALID_CORUN_LUT_40);
                bt_cmd->flags |= cpu_to_le32(BT_COEX_CORUNNING);
@@@ -832,8 -832,7 +832,8 @@@ static void iwl_mvm_bt_notif_iterator(v
        if (!vif->bss_conf.assoc)
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
  
 -      if (data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
 +      if (mvmvif->phy_ctxt &&
 +          data->notif->rrc_enabled & BIT(mvmvif->phy_ctxt->id))
                smps_mode = IEEE80211_SMPS_AUTOMATIC;
  
        IWL_DEBUG_COEX(data->mvm,
@@@ -1069,7 -1068,7 +1069,7 @@@ static void iwl_mvm_bt_rssi_iterator(vo
  }
  
  void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                              enum ieee80211_rssi_event rssi_event)
+                              enum ieee80211_rssi_event_data rssi_event)
  {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_bt_iterator_data data = {
@@@ -1168,10 -1167,16 +1168,10 @@@ bool iwl_mvm_bt_coex_is_mimo_allowed_ol
        return lut_type != BT_COEX_LOOSE_LUT;
  }
  
 -bool iwl_mvm_bt_coex_is_ant_avail_old(struct iwl_mvm *mvm, u8 ant)
 -{
 -      u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading);
 -      return ag < BT_HIGH_TRAFFIC;
 -}
 -
  bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm)
  {
        u32 ag = le32_to_cpu(mvm->last_bt_notif_old.bt_activity_grading);
 -      return ag == BT_OFF;
 +      return ag < BT_HIGH_TRAFFIC;
  }
  
  bool iwl_mvm_bt_coex_is_tpc_allowed_old(struct iwl_mvm *mvm,
@@@ -1208,7 -1213,7 +1208,7 @@@ int iwl_mvm_rx_ant_coupling_notif_old(s
                .dataflags = { IWL_HCMD_DFL_NOCOPY, },
        };
  
 -      if (!IWL_MVM_BT_COEX_CORUNNING)
 +      if (!iwl_mvm_bt_is_plcr_supported(mvm))
                return 0;
  
        lockdep_assert_held(&mvm->mutex);
@@@ -75,7 -75,6 +75,7 @@@
  #include "iwl-trans.h"
  #include "iwl-notif-wait.h"
  #include "iwl-eeprom-parse.h"
 +#include "iwl-fw-file.h"
  #include "sta.h"
  #include "fw-api.h"
  #include "constants.h"
@@@ -146,19 -145,6 +146,19 @@@ struct iwl_mvm_dump_ptrs 
        u32 op_mode_len;
  };
  
 +/**
 + * struct iwl_mvm_dump_desc - describes the dump
 + * @len: length of trig_desc->data
 + * @trig_desc: the description of the dump
 + */
 +struct iwl_mvm_dump_desc {
 +      size_t len;
 +      /* must be last */
 +      struct iwl_fw_error_dump_trigger_desc trig_desc;
 +};
 +
 +extern struct iwl_mvm_dump_desc iwl_mvm_dump_desc_assert;
 +
  struct iwl_mvm_phy_ctxt {
        u16 id;
        u16 color;
@@@ -351,12 -337,8 +351,12 @@@ struct iwl_mvm_vif_bf_data 
   * @beacon_skb: the skb used to hold the AP/GO beacon template
   * @smps_requests: the SMPS requests of differents parts of the driver,
   *    combined on update to yield the overall request to mac80211.
 + * @beacon_stats: beacon statistics, containing the # of received beacons,
 + *    # of received beacons accumulated over FW restart, and the current
 + *    average signal of beacons retrieved from the firmware
   */
  struct iwl_mvm_vif {
 +      struct iwl_mvm *mvm;
        u16 id;
        u16 color;
        u8 ap_sta_id;
        bool ps_disabled;
        struct iwl_mvm_vif_bf_data bf_data;
  
 +      struct {
 +              u32 num_beacons, accu_num_beacons;
 +              u8 avg_signal;
 +      } beacon_stats;
 +
        u32 ap_beacon_time;
  
        enum iwl_tsf_id tsf_id;
  #endif
  
  #ifdef CONFIG_IWLWIFI_DEBUGFS
 -      struct iwl_mvm *mvm;
        struct dentry *dbgfs_dir;
        struct dentry *dbgfs_slink;
        struct iwl_dbgfs_pm dbgfs_pm;
@@@ -615,13 -593,6 +615,13 @@@ struct iwl_mvm 
  
        struct mvm_statistics_rx rx_stats;
  
 +      struct {
 +              u64 rx_time;
 +              u64 tx_time;
 +              u64 on_time_rf;
 +              u64 on_time_scan;
 +      } radio_stats, accu_radio_stats;
 +
        u8 queue_to_mac80211[IWL_MAX_HW_QUEUES];
        atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES];
  
  
        struct iwl_mvm_frame_stats drv_rx_stats;
        spinlock_t drv_stats_lock;
 +      u16 dbgfs_rx_phyinfo;
  #endif
  
        struct iwl_mvm_phy_ctxt phy_ctxts[NUM_PHY_CTX];
  
        /* -1 for always, 0 for never, >0 for that many times */
        s8 restart_fw;
 -      struct work_struct fw_error_dump_wk;
 -      enum iwl_fw_dbg_conf fw_dbg_conf;
 +      u8 fw_dbg_conf;
 +      struct delayed_work fw_dump_wk;
 +      struct iwl_mvm_dump_desc *fw_dump_desc;
  
  #ifdef CONFIG_IWLWIFI_LEDS
        struct led_classdev led;
@@@ -855,7 -824,6 +855,7 @@@ enum iwl_mvm_status 
        IWL_MVM_STATUS_IN_D0I3,
        IWL_MVM_STATUS_ROC_AUX_RUNNING,
        IWL_MVM_STATUS_D3_RECONFIG,
 +      IWL_MVM_STATUS_DUMPING_FW_LOG,
  };
  
  static inline bool iwl_mvm_is_radio_killed(struct iwl_mvm *mvm)
@@@ -915,12 -883,6 +915,12 @@@ static inline bool iwl_mvm_is_scd_cfg_s
        return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG;
  }
  
 +static inline bool iwl_mvm_bt_is_plcr_supported(struct iwl_mvm *mvm)
 +{
 +      return (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BT_COEX_PLCR) &&
 +              IWL_MVM_BT_COEX_CORUNNING;
 +}
 +
  extern const u8 iwl_mvm_ac_to_tx_fifo[];
  
  struct iwl_rate_info {
@@@ -989,13 -951,12 +989,13 @@@ static inline void iwl_mvm_wait_for_asy
  }
  
  /* Statistics */
 -int iwl_mvm_rx_reply_statistics(struct iwl_mvm *mvm,
 -                              struct iwl_rx_cmd_buffer *rxb,
 -                              struct iwl_device_cmd *cmd);
 +void iwl_mvm_handle_rx_statistics(struct iwl_mvm *mvm,
 +                                struct iwl_rx_packet *pkt);
  int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
                          struct iwl_rx_cmd_buffer *rxb,
                          struct iwl_device_cmd *cmd);
 +int iwl_mvm_request_statistics(struct iwl_mvm *mvm, bool clear);
 +void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm);
  
  /* NVM */
  int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic);
@@@ -1111,6 -1072,13 +1111,6 @@@ int iwl_mvm_update_quotas(struct iwl_mv
  
  /* Scanning */
  int iwl_mvm_scan_size(struct iwl_mvm *mvm);
 -int iwl_mvm_scan_request(struct iwl_mvm *mvm,
 -                       struct ieee80211_vif *vif,
 -                       struct cfg80211_scan_request *req);
 -int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
 -                           struct iwl_device_cmd *cmd);
 -int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
 -                           struct iwl_device_cmd *cmd);
  int iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
  int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan);
  
@@@ -1121,8 -1089,14 +1121,8 @@@ int iwl_mvm_rx_scan_offload_complete_no
  int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
                                                struct iwl_rx_cmd_buffer *rxb,
                                                struct iwl_device_cmd *cmd);
 -int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
 -                            struct ieee80211_vif *vif,
 -                            struct cfg80211_sched_scan_request *req,
 -                            struct ieee80211_scan_ies *ies);
  int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
                                       struct cfg80211_sched_scan_request *req);
 -int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
 -                           struct cfg80211_sched_scan_request *req);
  int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
                               struct ieee80211_vif *vif,
                               struct cfg80211_sched_scan_request *req,
@@@ -1251,7 -1225,7 +1251,7 @@@ int iwl_mvm_rx_bt_coex_notif(struct iwl
                             struct iwl_rx_cmd_buffer *rxb,
                             struct iwl_device_cmd *cmd);
  void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                          enum ieee80211_rssi_event rssi_event);
+                          enum ieee80211_rssi_event_data);
  void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm);
  u16 iwl_mvm_coex_agg_time_limit(struct iwl_mvm *mvm,
                                struct ieee80211_sta *sta);
@@@ -1264,6 -1238,7 +1264,6 @@@ bool iwl_mvm_bt_coex_is_tpc_allowed(str
  u8 iwl_mvm_bt_coex_tx_prio(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
                           struct ieee80211_tx_info *info, u8 ac);
  
 -bool iwl_mvm_bt_coex_is_ant_avail_old(struct iwl_mvm *mvm, u8 ant);
  bool iwl_mvm_bt_coex_is_shared_ant_avail_old(struct iwl_mvm *mvm);
  void iwl_mvm_bt_coex_vif_change_old(struct iwl_mvm *mvm);
  int iwl_send_bt_init_conf_old(struct iwl_mvm *mvm);
@@@ -1271,7 -1246,7 +1271,7 @@@ int iwl_mvm_rx_bt_coex_notif_old(struc
                                 struct iwl_rx_cmd_buffer *rxb,
                                 struct iwl_device_cmd *cmd);
  void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                              enum ieee80211_rssi_event rssi_event);
+                              enum ieee80211_rssi_event_data);
  u16 iwl_mvm_coex_agg_time_limit_old(struct iwl_mvm *mvm,
                                    struct ieee80211_sta *sta);
  bool iwl_mvm_bt_coex_is_mimo_allowed_old(struct iwl_mvm *mvm,
@@@ -1377,6 -1352,9 +1377,6 @@@ static inline void iwl_mvm_enable_agg_t
        iwl_mvm_enable_txq(mvm, queue, ssn, &cfg, wdg_timeout);
  }
  
 -/* Assoc status */
 -bool iwl_mvm_is_idle(struct iwl_mvm *mvm);
 -
  /* Thermal management and CT-kill */
  void iwl_mvm_tt_tx_backoff(struct iwl_mvm *mvm, u32 backoff);
  void iwl_mvm_tt_temp_changed(struct iwl_mvm *mvm, u32 temp);
@@@ -1427,62 -1405,7 +1427,62 @@@ struct ieee80211_vif *iwl_mvm_get_bss_v
  void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
  void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
  
 -int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf id);
 -void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm);
 +int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 id);
 +int iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm, enum iwl_fw_dbg_trigger trig,
 +                         const char *str, size_t len, unsigned int delay);
 +int iwl_mvm_fw_dbg_collect_desc(struct iwl_mvm *mvm,
 +                              struct iwl_mvm_dump_desc *desc,
 +                              unsigned int delay);
 +void iwl_mvm_free_fw_dump_desc(struct iwl_mvm *mvm);
 +int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm,
 +                              struct iwl_fw_dbg_trigger_tlv *trigger,
 +                              const char *str, size_t len);
 +
 +static inline bool
 +iwl_fw_dbg_trigger_vif_match(struct iwl_fw_dbg_trigger_tlv *trig,
 +                           struct ieee80211_vif *vif)
 +{
 +      u32 trig_vif = le32_to_cpu(trig->vif_type);
 +
 +      return trig_vif == IWL_FW_DBG_CONF_VIF_ANY || vif->type == trig_vif;
 +}
 +
 +static inline bool
 +iwl_fw_dbg_trigger_stop_conf_match(struct iwl_mvm *mvm,
 +                                 struct iwl_fw_dbg_trigger_tlv *trig)
 +{
 +      return ((trig->mode & IWL_FW_DBG_TRIGGER_STOP) &&
 +              (mvm->fw_dbg_conf == FW_DBG_INVALID ||
 +              (BIT(mvm->fw_dbg_conf) & le32_to_cpu(trig->stop_conf_ids))));
 +}
 +
 +static inline bool
 +iwl_fw_dbg_trigger_check_stop(struct iwl_mvm *mvm,
 +                            struct ieee80211_vif *vif,
 +                            struct iwl_fw_dbg_trigger_tlv *trig)
 +{
 +      if (vif && !iwl_fw_dbg_trigger_vif_match(trig, vif))
 +              return false;
 +
 +      return iwl_fw_dbg_trigger_stop_conf_match(mvm, trig);
 +}
 +
 +static inline void
 +iwl_fw_dbg_trigger_simple_stop(struct iwl_mvm *mvm,
 +                             struct ieee80211_vif *vif,
 +                             enum iwl_fw_dbg_trigger trig,
 +                             const char *str, size_t len)
 +{
 +      struct iwl_fw_dbg_trigger_tlv *trigger;
 +
 +      if (!iwl_fw_dbg_trigger_enabled(mvm->fw, trig))
 +              return;
 +
 +      trigger = iwl_fw_dbg_get_trigger(mvm->fw, trig);
 +      if (!iwl_fw_dbg_trigger_check_stop(mvm, vif, trigger))
 +              return;
 +
 +      iwl_mvm_fw_dbg_collect_trig(mvm, trigger, str, len);
 +}
  
  #endif /* __IWL_MVM_H__ */
@@@ -330,6 -330,83 +330,83 @@@ static const struct ieee80211_rate hwsi
        { .bitrate = 540 }
  };
  
+ #define OUI_QCA 0x001374
+ #define QCA_NL80211_SUBCMD_TEST 1
+ enum qca_nl80211_vendor_subcmds {
+       QCA_WLAN_VENDOR_ATTR_TEST = 8,
+       QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_TEST
+ };
+ static const struct nla_policy
+ hwsim_vendor_test_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = {
+       [QCA_WLAN_VENDOR_ATTR_MAX] = { .type = NLA_U32 },
+ };
+ static int mac80211_hwsim_vendor_cmd_test(struct wiphy *wiphy,
+                                         struct wireless_dev *wdev,
+                                         const void *data, int data_len)
+ {
+       struct sk_buff *skb;
+       struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+       int err;
+       u32 val;
+       err = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len,
+                       hwsim_vendor_test_policy);
+       if (err)
+               return err;
+       if (!tb[QCA_WLAN_VENDOR_ATTR_TEST])
+               return -EINVAL;
+       val = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TEST]);
+       wiphy_debug(wiphy, "%s: test=%u\n", __func__, val);
+       /* Send a vendor event as a test. Note that this would not normally be
+        * done within a command handler, but rather, based on some other
+        * trigger. For simplicity, this command is used to trigger the event
+        * here.
+        *
+        * event_idx = 0 (index in mac80211_hwsim_vendor_commands)
+        */
+       skb = cfg80211_vendor_event_alloc(wiphy, wdev, 100, 0, GFP_KERNEL);
+       if (skb) {
+               /* skb_put() or nla_put() will fill up data within
+                * NL80211_ATTR_VENDOR_DATA.
+                */
+               /* Add vendor data */
+               nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 1);
+               /* Send the event - this will call nla_nest_end() */
+               cfg80211_vendor_event(skb, GFP_KERNEL);
+       }
+       /* Send a response to the command */
+       skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 10);
+       if (!skb)
+               return -ENOMEM;
+       /* skb_put() or nla_put() will fill up data within
+        * NL80211_ATTR_VENDOR_DATA
+        */
+       nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TEST, val + 2);
+       return cfg80211_vendor_cmd_reply(skb);
+ }
+ static struct wiphy_vendor_command mac80211_hwsim_vendor_commands[] = {
+       {
+               .info = { .vendor_id = OUI_QCA,
+                         .subcmd = QCA_NL80211_SUBCMD_TEST },
+               .flags = WIPHY_VENDOR_CMD_NEED_NETDEV,
+               .doit = mac80211_hwsim_vendor_cmd_test,
+       }
+ };
+ /* Advertise support vendor specific events */
+ static const struct nl80211_vendor_cmd_info mac80211_hwsim_vendor_events[] = {
+       { .vendor_id = OUI_QCA, .subcmd = 1 },
+ };
  static const struct ieee80211_iface_limit hwsim_if_limits[] = {
        { .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC) },
        { .max = 2048,  .types = BIT(NL80211_IFTYPE_STATION) |
@@@ -906,8 -983,7 +983,7 @@@ static void mac80211_hwsim_tx_frame_nl(
                goto nla_put_failure;
        }
  
-       if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER,
-                   ETH_ALEN, data->addresses[1].addr))
+       if (nla_put(skb, HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN, hdr->addr2))
                goto nla_put_failure;
  
        /* We get the skb->data */
                goto nla_put_failure;
  
        genlmsg_end(skb, msg_head);
 -      genlmsg_unicast(&init_net, skb, dst_portid);
 +      if (genlmsg_unicast(&init_net, skb, dst_portid))
 +              goto err_free_txskb;
  
        /* Enqueue the packet */
        skb_queue_tail(&data->pending, my_skb);
        return;
  
  nla_put_failure:
 +      nlmsg_free(skb);
 +err_free_txskb:
        printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
        ieee80211_free_txskb(hw, my_skb);
        data->tx_failed++;
@@@ -1522,21 -1595,16 +1598,16 @@@ static void mac80211_hwsim_bss_info_cha
                vp->aid = info->aid;
        }
  
-       if (changed & BSS_CHANGED_BEACON_INT) {
-               wiphy_debug(hw->wiphy, "  BCNINT: %d\n", info->beacon_int);
-               data->beacon_int = info->beacon_int * 1024;
-       }
        if (changed & BSS_CHANGED_BEACON_ENABLED) {
-               wiphy_debug(hw->wiphy, "  BCN EN: %d\n", info->enable_beacon);
+               wiphy_debug(hw->wiphy, "  BCN EN: %d (BI=%u)\n",
+                           info->enable_beacon, info->beacon_int);
                vp->bcn_en = info->enable_beacon;
                if (data->started &&
                    !hrtimer_is_queued(&data->beacon_timer.timer) &&
                    info->enable_beacon) {
                        u64 tsf, until_tbtt;
                        u32 bcn_int;
-                       if (WARN_ON(!data->beacon_int))
-                               data->beacon_int = 1000 * 1024;
+                       data->beacon_int = info->beacon_int * 1024;
                        tsf = mac80211_hwsim_get_tsf(hw, vif);
                        bcn_int = data->beacon_int;
                        until_tbtt = bcn_int - do_div(tsf, bcn_int);
                                mac80211_hwsim_bcn_en_iter, &count);
                        wiphy_debug(hw->wiphy, "  beaconing vifs remaining: %u",
                                    count);
-                       if (count == 0)
+                       if (count == 0) {
                                tasklet_hrtimer_cancel(&data->beacon_timer);
+                               data->beacon_int = 0;
+                       }
                }
        }
  
@@@ -1911,7 -1981,7 +1984,7 @@@ static void mac80211_hwsim_sw_scan_comp
  
        printk(KERN_DEBUG "hwsim sw_scan_complete\n");
        hwsim->scanning = false;
 -      memset(hwsim->scan_addr, 0, ETH_ALEN);
 +      eth_zero_addr(hwsim->scan_addr);
  
        mutex_unlock(&hwsim->mutex);
  }
@@@ -2267,7 -2337,7 +2340,7 @@@ static int mac80211_hwsim_new_radio(str
        skb_queue_head_init(&data->pending);
  
        SET_IEEE80211_DEV(hw, data->dev);
 -      memset(addr, 0, ETH_ALEN);
 +      eth_zero_addr(addr);
        addr[0] = 0x02;
        addr[3] = idx >> 8;
        addr[4] = idx;
        hw->max_rates = 4;
        hw->max_rate_tries = 11;
  
+       hw->wiphy->vendor_commands = mac80211_hwsim_vendor_commands;
+       hw->wiphy->n_vendor_commands =
+               ARRAY_SIZE(mac80211_hwsim_vendor_commands);
+       hw->wiphy->vendor_events = mac80211_hwsim_vendor_events;
+       hw->wiphy->n_vendor_events = ARRAY_SIZE(mac80211_hwsim_vendor_events);
        if (param->reg_strict)
                hw->wiphy->regulatory_flags |= REGULATORY_STRICT_REG;
        if (param->regd) {
@@@ -2600,7 -2676,7 +2679,7 @@@ static void hwsim_mon_setup(struct net_
        ether_setup(dev);
        dev->tx_queue_len = 0;
        dev->type = ARPHRD_IEEE80211_RADIOTAP;
 -      memset(dev->dev_addr, 0, ETH_ALEN);
 +      eth_zero_addr(dev->dev_addr);
        dev->dev_addr[0] = 0x12;
  }
  
@@@ -2611,7 -2687,7 +2690,7 @@@ static struct mac80211_hwsim_data *get_
  
        spin_lock_bh(&hwsim_radio_lock);
        list_for_each_entry(data, &hwsim_radios, list) {
-               if (memcmp(data->addresses[1].addr, addr, ETH_ALEN) == 0) {
+               if (mac80211_hwsim_addr_match(data, addr)) {
                        _found = true;
                        break;
                }
@@@ -1563,7 -1563,7 +1563,7 @@@ mwifiex_cfg80211_del_station(struct wip
  
        wiphy_dbg(wiphy, "%s: mac address %pM\n", __func__, params->mac);
  
 -      memset(deauth_mac, 0, ETH_ALEN);
 +      eth_zero_addr(deauth_mac);
  
        spin_lock_irqsave(&priv->sta_list_spinlock, flags);
        sta_node = mwifiex_get_sta_entry(priv, params->mac);
@@@ -1786,7 -1786,7 +1786,7 @@@ mwifiex_cfg80211_disconnect(struct wiph
        wiphy_dbg(wiphy, "info: successfully disconnected from %pM:"
                " reason code %d\n", priv->cfg_bssid, reason_code);
  
 -      memset(priv->cfg_bssid, 0, ETH_ALEN);
 +      eth_zero_addr(priv->cfg_bssid);
        priv->hs2_enabled = false;
  
        return 0;
@@@ -1954,13 -1954,13 +1954,13 @@@ done
                if (mode == NL80211_IFTYPE_ADHOC)
                        bss = cfg80211_get_bss(priv->wdev.wiphy, channel,
                                               bssid, ssid, ssid_len,
-                                              WLAN_CAPABILITY_IBSS,
-                                              WLAN_CAPABILITY_IBSS);
+                                              IEEE80211_BSS_TYPE_IBSS,
+                                              IEEE80211_PRIVACY_ANY);
                else
                        bss = cfg80211_get_bss(priv->wdev.wiphy, channel,
                                               bssid, ssid, ssid_len,
-                                              WLAN_CAPABILITY_ESS,
-                                              WLAN_CAPABILITY_ESS);
+                                              IEEE80211_BSS_TYPE_ESS,
+                                              IEEE80211_PRIVACY_ANY);
  
                if (!bss) {
                        if (is_scanning_required) {
@@@ -2046,7 -2046,7 +2046,7 @@@ mwifiex_cfg80211_connect(struct wiphy *
                dev_dbg(priv->adapter->dev,
                        "info: association to bssid %pM failed\n",
                        priv->cfg_bssid);
 -              memset(priv->cfg_bssid, 0, ETH_ALEN);
 +              eth_zero_addr(priv->cfg_bssid);
  
                if (ret > 0)
                        cfg80211_connect_result(priv->netdev, priv->cfg_bssid,
@@@ -2194,7 -2194,7 +2194,7 @@@ mwifiex_cfg80211_leave_ibss(struct wiph
        if (mwifiex_deauthenticate(priv, NULL))
                return -EFAULT;
  
 -      memset(priv->cfg_bssid, 0, ETH_ALEN);
 +      eth_zero_addr(priv->cfg_bssid);
  
        return 0;
  }
@@@ -2397,11 -2397,13 +2397,12 @@@ mwifiex_setup_ht_caps(struct ieee80211_
        ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
  }
  
 -#define MWIFIEX_MAX_WQ_LEN  30
  /*
-  *  create a new virtual interface with the given name
+  *  create a new virtual interface with the given name and name assign type
   */
  struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
                                              const char *name,
+                                             unsigned char name_assign_type,
                                              enum nl80211_iftype type,
                                              u32 *flags,
                                              struct vif_params *params)
        struct mwifiex_private *priv;
        struct net_device *dev;
        void *mdev_priv;
 -      char dfs_cac_str[MWIFIEX_MAX_WQ_LEN], dfs_chsw_str[MWIFIEX_MAX_WQ_LEN];
  
        if (!adapter)
                return ERR_PTR(-EFAULT);
        }
  
        dev = alloc_netdev_mqs(sizeof(struct mwifiex_private *), name,
-                              NET_NAME_UNKNOWN, ether_setup,
+                              name_assign_type, ether_setup,
                               IEEE80211_NUM_ACS, 1);
        if (!dev) {
                wiphy_err(wiphy, "no memory available for netdevice\n");
                return ERR_PTR(-EFAULT);
        }
  
 -      strcpy(dfs_cac_str, "MWIFIEX_DFS_CAC");
 -      strcat(dfs_cac_str, name);
 -      priv->dfs_cac_workqueue = alloc_workqueue(dfs_cac_str,
 +      priv->dfs_cac_workqueue = alloc_workqueue("MWIFIEX_DFS_CAC%s",
                                                  WQ_HIGHPRI |
                                                  WQ_MEM_RECLAIM |
 -                                                WQ_UNBOUND, 1);
 +                                                WQ_UNBOUND, 1, name);
        if (!priv->dfs_cac_workqueue) {
                wiphy_err(wiphy, "cannot register virtual network device\n");
                free_netdev(dev);
  
        INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue);
  
 -      strcpy(dfs_chsw_str, "MWIFIEX_DFS_CHSW");
 -      strcat(dfs_chsw_str, name);
 -      priv->dfs_chan_sw_workqueue = alloc_workqueue(dfs_chsw_str,
 +      priv->dfs_chan_sw_workqueue = alloc_workqueue("MWIFIEX_DFS_CHSW%s",
                                                      WQ_HIGHPRI | WQ_UNBOUND |
 -                                                    WQ_MEM_RECLAIM, 1);
 +                                                    WQ_MEM_RECLAIM, 1, name);
        if (!priv->dfs_chan_sw_workqueue) {
                wiphy_err(wiphy, "cannot register virtual network device\n");
                free_netdev(dev);
@@@ -190,16 -190,14 +190,16 @@@ int mwifiex_main_process(struct mwifiex
  
        /* Check if already processing */
        if (adapter->mwifiex_processing) {
 +              adapter->more_task_flag = true;
                spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
                goto exit_main_proc;
        } else {
                adapter->mwifiex_processing = true;
 -              spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
        }
  process_start:
        do {
 +              adapter->more_task_flag = false;
 +              spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
                if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) ||
                    (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY))
                        break;
                        adapter->pm_wakeup_fw_try = true;
                        mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3));
                        adapter->if_ops.wakeup(adapter);
 +                      spin_lock_irqsave(&adapter->main_proc_lock, flags);
                        continue;
                }
  
                if ((adapter->ps_state == PS_STATE_SLEEP) ||
                    (adapter->ps_state == PS_STATE_PRE_SLEEP) ||
                    (adapter->ps_state == PS_STATE_SLEEP_CFM) ||
 -                  adapter->tx_lock_flag)
 +                  adapter->tx_lock_flag){
 +                      spin_lock_irqsave(&adapter->main_proc_lock, flags);
                        continue;
 +              }
  
                if (!adapter->cmd_sent && !adapter->curr_cmd) {
                        if (mwifiex_exec_next_cmd(adapter) == -1) {
                        }
                        break;
                }
 +              spin_lock_irqsave(&adapter->main_proc_lock, flags);
        } while (true);
  
        spin_lock_irqsave(&adapter->main_proc_lock, flags);
 -      if (!adapter->delay_main_work &&
 -          (adapter->int_status || IS_CARD_RX_RCVD(adapter))) {
 -              spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
 +      if (adapter->more_task_flag)
                goto process_start;
 -      }
 -
        adapter->mwifiex_processing = false;
        spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
  
@@@ -468,7 -466,7 +468,7 @@@ static void mwifiex_fw_dpc(const struc
  
        rtnl_lock();
        /* Create station interface by default */
-       wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d",
+       wdev = mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", NET_NAME_ENUM,
                                        NL80211_IFTYPE_STATION, NULL, NULL);
        if (IS_ERR(wdev)) {
                dev_err(adapter->dev, "cannot create default STA interface\n");
        }
  
        if (driver_mode & MWIFIEX_DRIVER_MODE_UAP) {
-               wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d",
+               wdev = mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", NET_NAME_ENUM,
                                                NL80211_IFTYPE_AP, NULL, NULL);
                if (IS_ERR(wdev)) {
                        dev_err(adapter->dev, "cannot create AP interface\n");
        }
  
        if (driver_mode & MWIFIEX_DRIVER_MODE_P2P) {
-               wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d",
+               wdev = mwifiex_add_virtual_intf(adapter->wiphy, "p2p%d", NET_NAME_ENUM,
                                                NL80211_IFTYPE_P2P_CLIENT, NULL,
                                                NULL);
                if (IS_ERR(wdev)) {
@@@ -140,9 -140,6 +140,9 @@@ enum 
  
  #define MWIFIEX_DRV_INFO_SIZE_MAX 0x40000
  
 +/* Address alignment */
 +#define MWIFIEX_ALIGN_ADDR(p, a) (((long)(p) + (a) - 1) & ~((a) - 1))
 +
  struct mwifiex_dbg {
        u32 num_cmd_host_to_card_failure;
        u32 num_cmd_sleep_cfm_host_to_card_failure;
@@@ -777,7 -774,6 +777,7 @@@ struct mwifiex_adapter 
        /* spin lock for main process */
        spinlock_t main_proc_lock;
        u32 mwifiex_processing;
 +      u8 more_task_flag;
        u16 tx_buf_size;
        u16 curr_tx_buf_size;
        u32 ioport;
@@@ -1322,6 -1318,7 +1322,7 @@@ u8 mwifiex_chan_type_to_sec_chan_offset
  
  struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
                                              const char *name,
+                                             unsigned char name_assign_type,
                                              enum nl80211_iftype type,
                                              u32 *flags,
                                              struct vif_params *params);
@@@ -1421,7 -1418,6 +1422,7 @@@ u8 mwifiex_adjust_data_rate(struct mwif
                            u8 rx_rate, u8 ht_info);
  
  void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter);
 +void *mwifiex_alloc_rx_buf(int rx_len, gfp_t flags);
  
  #ifdef CONFIG_DEBUG_FS
  void mwifiex_debugfs_init(void);
diff --combined include/net/cfg80211.h
@@@ -214,6 -214,39 +214,39 @@@ enum ieee80211_rate_flags 
        IEEE80211_RATE_SUPPORTS_10MHZ   = 1<<6,
  };
  
+ /**
+  * enum ieee80211_bss_type - BSS type filter
+  *
+  * @IEEE80211_BSS_TYPE_ESS: Infrastructure BSS
+  * @IEEE80211_BSS_TYPE_PBSS: Personal BSS
+  * @IEEE80211_BSS_TYPE_IBSS: Independent BSS
+  * @IEEE80211_BSS_TYPE_MBSS: Mesh BSS
+  * @IEEE80211_BSS_TYPE_ANY: Wildcard value for matching any BSS type
+  */
+ enum ieee80211_bss_type {
+       IEEE80211_BSS_TYPE_ESS,
+       IEEE80211_BSS_TYPE_PBSS,
+       IEEE80211_BSS_TYPE_IBSS,
+       IEEE80211_BSS_TYPE_MBSS,
+       IEEE80211_BSS_TYPE_ANY
+ };
+ /**
+  * enum ieee80211_privacy - BSS privacy filter
+  *
+  * @IEEE80211_PRIVACY_ON: privacy bit set
+  * @IEEE80211_PRIVACY_OFF: privacy bit clear
+  * @IEEE80211_PRIVACY_ANY: Wildcard value for matching any privacy setting
+  */
+ enum ieee80211_privacy {
+       IEEE80211_PRIVACY_ON,
+       IEEE80211_PRIVACY_OFF,
+       IEEE80211_PRIVACY_ANY
+ };
+ #define IEEE80211_PRIVACY(x)  \
+       ((x) ? IEEE80211_PRIVACY_ON : IEEE80211_PRIVACY_OFF)
  /**
   * struct ieee80211_rate - bitrate definition
   *
@@@ -2423,6 -2456,7 +2456,7 @@@ struct cfg80211_ops 
  
        struct wireless_dev * (*add_virtual_intf)(struct wiphy *wiphy,
                                                  const char *name,
+                                                 unsigned char name_assign_type,
                                                  enum nl80211_iftype type,
                                                  u32 *flags,
                                                  struct vif_params *params);
@@@ -3183,8 -3217,10 +3217,8 @@@ struct wiphy 
        const struct ieee80211_ht_cap *ht_capa_mod_mask;
        const struct ieee80211_vht_cap *vht_capa_mod_mask;
  
 -#ifdef CONFIG_NET_NS
        /* the network namespace this phy lives in currently */
 -      struct net *_net;
 -#endif
 +      possible_net_t _net;
  
  #ifdef CONFIG_CFG80211_WEXT
        const struct iw_handler_def *wext;
@@@ -4010,14 -4046,16 +4044,16 @@@ struct cfg80211_bss *cfg80211_get_bss(s
                                      struct ieee80211_channel *channel,
                                      const u8 *bssid,
                                      const u8 *ssid, size_t ssid_len,
-                                     u16 capa_mask, u16 capa_val);
+                                     enum ieee80211_bss_type bss_type,
+                                     enum ieee80211_privacy);
  static inline struct cfg80211_bss *
  cfg80211_get_ibss(struct wiphy *wiphy,
                  struct ieee80211_channel *channel,
                  const u8 *ssid, size_t ssid_len)
  {
        return cfg80211_get_bss(wiphy, channel, NULL, ssid, ssid_len,
-                               WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+                               IEEE80211_BSS_TYPE_IBSS,
+                               IEEE80211_PRIVACY_ANY);
  }
  
  /**
@@@ -4258,6 -4296,7 +4294,7 @@@ struct sk_buff *__cfg80211_alloc_reply_
                                           int approxlen);
  
  struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+                                          struct wireless_dev *wdev,
                                           enum nl80211_commands cmd,
                                           enum nl80211_attrs attr,
                                           int vendor_event_idx,
@@@ -4312,6 -4351,7 +4349,7 @@@ int cfg80211_vendor_cmd_reply(struct sk
  /**
   * cfg80211_vendor_event_alloc - allocate vendor-specific event skb
   * @wiphy: the wiphy
+  * @wdev: the wireless device
   * @event_idx: index of the vendor event in the wiphy's vendor_events
   * @approxlen: an upper bound of the length of the data that will
   *    be put into the skb
   * This function allocates and pre-fills an skb for an event on the
   * vendor-specific multicast group.
   *
+  * If wdev != NULL, both the ifindex and identifier of the specified
+  * wireless device are added to the event message before the vendor data
+  * attribute.
+  *
   * When done filling the skb, call cfg80211_vendor_event() with the
   * skb to send the event.
   *
   * Return: An allocated and pre-filled skb. %NULL if any errors happen.
   */
  static inline struct sk_buff *
- cfg80211_vendor_event_alloc(struct wiphy *wiphy, int approxlen,
-                           int event_idx, gfp_t gfp)
+ cfg80211_vendor_event_alloc(struct wiphy *wiphy, struct wireless_dev *wdev,
+                            int approxlen, int event_idx, gfp_t gfp)
  {
-       return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_VENDOR,
+       return __cfg80211_alloc_event_skb(wiphy, wdev, NL80211_CMD_VENDOR,
                                          NL80211_ATTR_VENDOR_DATA,
                                          event_idx, approxlen, gfp);
  }
@@@ -4430,7 -4474,7 +4472,7 @@@ static inline int cfg80211_testmode_rep
  static inline struct sk_buff *
  cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp)
  {
-       return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_TESTMODE,
+       return __cfg80211_alloc_event_skb(wiphy, NULL, NL80211_CMD_TESTMODE,
                                          NL80211_ATTR_TESTDATA, -1,
                                          approxlen, gfp);
  }
@@@ -4860,6 -4904,17 +4902,17 @@@ void cfg80211_ch_switch_started_notify(
  bool ieee80211_operating_class_to_band(u8 operating_class,
                                       enum ieee80211_band *band);
  
+ /**
+  * ieee80211_chandef_to_operating_class - convert chandef to operation class
+  *
+  * @chandef: the chandef to convert
+  * @op_class: a pointer to the resulting operating class
+  *
+  * Returns %true if the conversion was successful, %false otherwise.
+  */
+ bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
+                                         u8 *op_class);
  /*
   * cfg80211_tdls_oper_request - request userspace to perform TDLS operation
   * @dev: the device on which the operation is requested
diff --combined net/mac80211/cfg.c
@@@ -24,6 -24,7 +24,7 @@@
  
  static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
                                                const char *name,
+                                               unsigned char name_assign_type,
                                                enum nl80211_iftype type,
                                                u32 *flags,
                                                struct vif_params *params)
@@@ -33,7 -34,7 +34,7 @@@
        struct ieee80211_sub_if_data *sdata;
        int err;
  
-       err = ieee80211_if_add(local, name, &wdev, type, params);
+       err = ieee80211_if_add(local, name, name_assign_type, &wdev, type, params);
        if (err)
                return ERR_PTR(err);
  
@@@ -977,6 -978,14 +978,14 @@@ static int sta_apply_auth_flags(struct 
        if (mask & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
            set & BIT(NL80211_STA_FLAG_ASSOCIATED) &&
            !test_sta_flag(sta, WLAN_STA_ASSOC)) {
+               /*
+                * When peer becomes associated, init rate control as
+                * well. Some drivers require rate control initialized
+                * before drv_sta_state() is called.
+                */
+               if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+                       rate_control_rate_init(sta);
                ret = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
                if (ret)
                        return ret;
@@@ -1050,6 -1059,10 +1059,10 @@@ static int sta_apply_parameters(struct 
                }
        }
  
+       if (mask & BIT(NL80211_STA_FLAG_WME) &&
+           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)) {
                ret = sta_apply_auth_flags(local, sta, mask, set);
                        clear_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE);
        }
  
-       if (mask & BIT(NL80211_STA_FLAG_WME))
-               sta->sta.wme = set & BIT(NL80211_STA_FLAG_WME);
        if (mask & BIT(NL80211_STA_FLAG_MFP)) {
+               sta->sta.mfp = !!(set & BIT(NL80211_STA_FLAG_MFP));
                if (set & BIT(NL80211_STA_FLAG_MFP))
                        set_sta_flag(sta, WLAN_STA_MFP);
                else
@@@ -1377,11 -1388,6 +1388,6 @@@ static int ieee80211_change_station(str
        if (err)
                goto out_err;
  
-       /* When peer becomes authorized, init rate control as well */
-       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) &&
-           test_sta_flag(sta, WLAN_STA_AUTHORIZED))
-               rate_control_rate_init(sta);
        mutex_unlock(&local->sta_mtx);
  
        if ((sdata->vif.type == NL80211_IFTYPE_AP ||
@@@ -1488,7 -1494,7 +1494,7 @@@ static void mpath_set_pinfo(struct mesh
        if (next_hop_sta)
                memcpy(next_hop, next_hop_sta->sta.addr, ETH_ALEN);
        else
 -              memset(next_hop, 0, ETH_ALEN);
 +              eth_zero_addr(next_hop);
  
        memset(pinfo, 0, sizeof(*pinfo));
  
@@@ -2273,7 -2279,6 +2279,6 @@@ int __ieee80211_request_smps_ap(struct 
  {
        struct sta_info *sta;
        enum ieee80211_smps_mode old_req;
-       int i;
  
        if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP))
                return -EINVAL;
        }
  
        ht_dbg(sdata,
-              "SMSP %d requested in AP mode, sending Action frame to %d stations\n",
+              "SMPS %d requested in AP mode, sending Action frame to %d stations\n",
               smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta));
  
        mutex_lock(&sdata->local->sta_mtx);
-       for (i = 0; i < STA_HASH_SIZE; i++) {
-               for (sta = rcu_dereference_protected(sdata->local->sta_hash[i],
-                               lockdep_is_held(&sdata->local->sta_mtx));
-                    sta;
-                    sta = rcu_dereference_protected(sta->hnext,
-                               lockdep_is_held(&sdata->local->sta_mtx))) {
-                       /*
-                        * Only stations associated to our AP and
-                        * associated VLANs
-                        */
-                       if (sta->sdata->bss != &sdata->u.ap)
-                               continue;
+       list_for_each_entry(sta, &sdata->local->sta_list, list) {
+               /*
+                * Only stations associated to our AP and
+                * associated VLANs
+                */
+               if (sta->sdata->bss != &sdata->u.ap)
+                       continue;
  
-                       /* This station doesn't support MIMO - skip it */
-                       if (sta_info_tx_streams(sta) == 1)
-                               continue;
+               /* This station doesn't support MIMO - skip it */
+               if (sta_info_tx_streams(sta) == 1)
+                       continue;
  
-                       /*
-                        * Don't wake up a STA just to send the action frame
-                        * unless we are getting more restrictive.
-                        */
-                       if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
-                           !ieee80211_smps_is_restrictive(sta->known_smps_mode,
-                                                          smps_mode)) {
-                               ht_dbg(sdata,
-                                      "Won't send SMPS to sleeping STA %pM\n",
-                                      sta->sta.addr);
-                               continue;
-                       }
+               /*
+                * Don't wake up a STA just to send the action frame
+                * unless we are getting more restrictive.
+                */
+               if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
+                   !ieee80211_smps_is_restrictive(sta->known_smps_mode,
+                                                  smps_mode)) {
+                       ht_dbg(sdata, "Won't send SMPS to sleeping STA %pM\n",
+                              sta->sta.addr);
+                       continue;
+               }
  
-                       /*
-                        * If the STA is not authorized, wait until it gets
-                        * authorized and the action frame will be sent then.
-                        */
-                       if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
-                               continue;
+               /*
+                * If the STA is not authorized, wait until it gets
+                * authorized and the action frame will be sent then.
+                */
+               if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+                       continue;
  
-                       ht_dbg(sdata, "Sending SMPS to %pM\n", sta->sta.addr);
-                       ieee80211_send_smps_action(sdata, smps_mode,
-                                                  sta->sta.addr,
-                                                  sdata->vif.bss_conf.bssid);
-               }
+               ht_dbg(sdata, "Sending SMPS to %pM\n", sta->sta.addr);
+               ieee80211_send_smps_action(sdata, smps_mode, sta->sta.addr,
+                                          sdata->vif.bss_conf.bssid);
        }
        mutex_unlock(&sdata->local->sta_mtx);
  
@@@ -3581,7 -3578,7 +3578,7 @@@ static int ieee80211_probe_client(struc
                nullfunc->qos_ctrl = cpu_to_le16(7);
  
        local_bh_disable();
-       ieee80211_xmit(sdata, skb);
+       ieee80211_xmit(sdata, sta, skb);
        local_bh_enable();
        rcu_read_unlock();
  
diff --combined net/mac80211/ibss.c
@@@ -188,6 -188,16 +188,16 @@@ ieee80211_ibss_build_presp(struct ieee8
                 */
                pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
                                                 chandef, 0);
+               /* add VHT capability and information IEs */
+               if (chandef->width != NL80211_CHAN_WIDTH_20 &&
+                   chandef->width != NL80211_CHAN_WIDTH_40 &&
+                   sband->vht_cap.vht_supported) {
+                       pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
+                                                        sband->vht_cap.cap);
+                       pos = ieee80211_ie_build_vht_oper(pos, &sband->vht_cap,
+                                                         chandef);
+               }
        }
  
        if (local->hw.queues >= IEEE80211_NUM_ACS)
@@@ -249,8 -259,6 +259,6 @@@ static void __ieee80211_sta_join_ibss(s
        if (presp)
                kfree_rcu(presp, rcu_head);
  
-       sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
        /* make a copy of the chandef, it could be modified below. */
        chandef = *req_chandef;
        chan = chandef.chan;
@@@ -417,6 -425,11 +425,11 @@@ static void ieee80211_sta_join_ibss(str
                                        NL80211_CHAN_WIDTH_20_NOHT);
                chandef.width = sdata->u.ibss.chandef.width;
                break;
+       case NL80211_CHAN_WIDTH_80:
+       case NL80211_CHAN_WIDTH_160:
+               chandef = sdata->u.ibss.chandef;
+               chandef.chan = cbss->channel;
+               break;
        default:
                /* fall back to 20 MHz for unsupported modes */
                cfg80211_chandef_create(&chandef, cbss->channel,
@@@ -470,22 -483,19 +483,19 @@@ int ieee80211_ibss_csa_beacon(struct ie
        struct beacon_data *presp, *old_presp;
        struct cfg80211_bss *cbss;
        const struct cfg80211_bss_ies *ies;
-       u16 capability;
+       u16 capability = 0;
        u64 tsf;
        int ret = 0;
  
        sdata_assert_lock(sdata);
  
-       capability = WLAN_CAPABILITY_IBSS;
        if (ifibss->privacy)
-               capability |= WLAN_CAPABILITY_PRIVACY;
+               capability = WLAN_CAPABILITY_PRIVACY;
  
        cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan,
                                ifibss->bssid, ifibss->ssid,
-                               ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
-                               WLAN_CAPABILITY_PRIVACY,
-                               capability);
+                               ifibss->ssid_len, IEEE80211_BSS_TYPE_IBSS,
+                               IEEE80211_PRIVACY(ifibss->privacy));
  
        if (WARN_ON(!cbss)) {
                ret = -EINVAL;
@@@ -525,23 -535,17 +535,17 @@@ int ieee80211_ibss_finish_csa(struct ie
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
        struct cfg80211_bss *cbss;
        int err, changed = 0;
-       u16 capability;
  
        sdata_assert_lock(sdata);
  
        /* update cfg80211 bss information with the new channel */
        if (!is_zero_ether_addr(ifibss->bssid)) {
-               capability = WLAN_CAPABILITY_IBSS;
-               if (ifibss->privacy)
-                       capability |= WLAN_CAPABILITY_PRIVACY;
                cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
                                        ifibss->chandef.chan,
                                        ifibss->bssid, ifibss->ssid,
-                                       ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
-                                       WLAN_CAPABILITY_PRIVACY,
-                                       capability);
+                                       ifibss->ssid_len,
+                                       IEEE80211_BSS_TYPE_IBSS,
+                                       IEEE80211_PRIVACY(ifibss->privacy));
                /* XXX: should not really modify cfg80211 data */
                if (cbss) {
                        cbss->channel = sdata->csa_chandef.chan;
@@@ -682,19 -686,13 +686,13 @@@ static void ieee80211_ibss_disconnect(s
        struct cfg80211_bss *cbss;
        struct beacon_data *presp;
        struct sta_info *sta;
-       u16 capability;
  
        if (!is_zero_ether_addr(ifibss->bssid)) {
-               capability = WLAN_CAPABILITY_IBSS;
-               if (ifibss->privacy)
-                       capability |= WLAN_CAPABILITY_PRIVACY;
                cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
                                        ifibss->bssid, ifibss->ssid,
-                                       ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
-                                       WLAN_CAPABILITY_PRIVACY,
-                                       capability);
+                                       ifibss->ssid_len,
+                                       IEEE80211_BSS_TYPE_IBSS,
+                                       IEEE80211_PRIVACY(ifibss->privacy));
  
                if (cbss) {
                        cfg80211_unlink_bss(local->hw.wiphy, cbss);
@@@ -980,110 -978,140 +978,140 @@@ static void ieee80211_rx_mgmt_auth_ibss
                            mgmt->sa, sdata->u.ibss.bssid, NULL, 0, 0, 0);
  }
  
- static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
-                                 struct ieee80211_mgmt *mgmt, size_t len,
-                                 struct ieee80211_rx_status *rx_status,
-                                 struct ieee802_11_elems *elems)
+ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
+                                     struct ieee80211_mgmt *mgmt, size_t len,
+                                     struct ieee80211_rx_status *rx_status,
+                                     struct ieee802_11_elems *elems,
+                                     struct ieee80211_channel *channel)
  {
-       struct ieee80211_local *local = sdata->local;
-       struct cfg80211_bss *cbss;
-       struct ieee80211_bss *bss;
        struct sta_info *sta;
-       struct ieee80211_channel *channel;
-       u64 beacon_timestamp, rx_timestamp;
-       u32 supp_rates = 0;
        enum ieee80211_band band = rx_status->band;
        enum nl80211_bss_scan_width scan_width;
+       struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
        bool rates_updated = false;
+       u32 supp_rates = 0;
  
-       channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
-       if (!channel)
+       if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
                return;
  
-       if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
-           ether_addr_equal(mgmt->bssid, sdata->u.ibss.bssid)) {
+       if (!ether_addr_equal(mgmt->bssid, sdata->u.ibss.bssid))
+               return;
  
-               rcu_read_lock();
-               sta = sta_info_get(sdata, mgmt->sa);
-               if (elems->supp_rates) {
-                       supp_rates = ieee80211_sta_get_rates(sdata, elems,
-                                                            band, NULL);
-                       if (sta) {
-                               u32 prev_rates;
-                               prev_rates = sta->sta.supp_rates[band];
-                               /* make sure mandatory rates are always added */
-                               scan_width = NL80211_BSS_CHAN_WIDTH_20;
-                               if (rx_status->flag & RX_FLAG_5MHZ)
-                                       scan_width = NL80211_BSS_CHAN_WIDTH_5;
-                               if (rx_status->flag & RX_FLAG_10MHZ)
-                                       scan_width = NL80211_BSS_CHAN_WIDTH_10;
-                               sta->sta.supp_rates[band] = supp_rates |
-                                       ieee80211_mandatory_rates(sband,
-                                                                 scan_width);
-                               if (sta->sta.supp_rates[band] != prev_rates) {
-                                       ibss_dbg(sdata,
-                                                "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n",
-                                                sta->sta.addr, prev_rates,
-                                                sta->sta.supp_rates[band]);
-                                       rates_updated = true;
-                               }
-                       } else {
-                               rcu_read_unlock();
-                               sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
-                                               mgmt->sa, supp_rates);
+       rcu_read_lock();
+       sta = sta_info_get(sdata, mgmt->sa);
+       if (elems->supp_rates) {
+               supp_rates = ieee80211_sta_get_rates(sdata, elems,
+                                                    band, NULL);
+               if (sta) {
+                       u32 prev_rates;
+                       prev_rates = sta->sta.supp_rates[band];
+                       /* make sure mandatory rates are always added */
+                       scan_width = NL80211_BSS_CHAN_WIDTH_20;
+                       if (rx_status->flag & RX_FLAG_5MHZ)
+                               scan_width = NL80211_BSS_CHAN_WIDTH_5;
+                       if (rx_status->flag & RX_FLAG_10MHZ)
+                               scan_width = NL80211_BSS_CHAN_WIDTH_10;
+                       sta->sta.supp_rates[band] = supp_rates |
+                               ieee80211_mandatory_rates(sband, scan_width);
+                       if (sta->sta.supp_rates[band] != prev_rates) {
+                               ibss_dbg(sdata,
+                                        "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n",
+                                        sta->sta.addr, prev_rates,
+                                        sta->sta.supp_rates[band]);
+                               rates_updated = true;
                        }
+               } else {
+                       rcu_read_unlock();
+                       sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid,
+                                                    mgmt->sa, supp_rates);
                }
+       }
  
-               if (sta && elems->wmm_info)
-                       sta->sta.wme = true;
-               if (sta && elems->ht_operation && elems->ht_cap_elem &&
-                   sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
-                   sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_5 &&
-                   sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_10) {
-                       /* we both use HT */
-                       struct ieee80211_ht_cap htcap_ie;
-                       struct cfg80211_chan_def chandef;
-                       ieee80211_ht_oper_to_chandef(channel,
-                                                    elems->ht_operation,
-                                                    &chandef);
-                       memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
-                       /*
-                        * fall back to HT20 if we don't use or use
-                        * the other extension channel
-                        */
-                       if (chandef.center_freq1 !=
-                           sdata->u.ibss.chandef.center_freq1)
-                               htcap_ie.cap_info &=
-                                       cpu_to_le16(~IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-                       rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(
-                                               sdata, sband, &htcap_ie, sta);
+       if (sta && elems->wmm_info && local->hw.queues >= IEEE80211_NUM_ACS)
+               sta->sta.wme = true;
+       if (sta && elems->ht_operation && elems->ht_cap_elem &&
+           sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
+           sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_5 &&
+           sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_10) {
+               /* we both use HT */
+               struct ieee80211_ht_cap htcap_ie;
+               struct cfg80211_chan_def chandef;
+               enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth;
+               ieee80211_ht_oper_to_chandef(channel,
+                                            elems->ht_operation,
+                                            &chandef);
+               memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
+               rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
+                                                                  &htcap_ie,
+                                                                  sta);
+               if (elems->vht_operation && elems->vht_cap_elem &&
+                   sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_20 &&
+                   sdata->u.ibss.chandef.width != NL80211_CHAN_WIDTH_40) {
+                       /* we both use VHT */
+                       struct ieee80211_vht_cap cap_ie;
+                       struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap;
+                       ieee80211_vht_oper_to_chandef(channel,
+                                                     elems->vht_operation,
+                                                     &chandef);
+                       memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
+                       ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
+                                                           &cap_ie, sta);
+                       if (memcmp(&cap, &sta->sta.vht_cap, sizeof(cap)))
+                               rates_updated |= true;
                }
  
-               if (sta && rates_updated) {
-                       u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
-                       u8 rx_nss = sta->sta.rx_nss;
+               if (bw != sta->sta.bandwidth)
+                       rates_updated |= true;
  
-                       /* 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;
+               if (!cfg80211_chandef_compatible(&sdata->u.ibss.chandef,
+                                                &chandef))
+                       WARN_ON_ONCE(1);
+       }
  
-                       drv_sta_rc_update(local, sdata, &sta->sta, changed);
-               }
+       if (sta && rates_updated) {
+               u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
+               u8 rx_nss = sta->sta.rx_nss;
  
-               rcu_read_unlock();
+               /* 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();
+ }
+ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
+                                 struct ieee80211_mgmt *mgmt, size_t len,
+                                 struct ieee80211_rx_status *rx_status,
+                                 struct ieee802_11_elems *elems)
+ {
+       struct ieee80211_local *local = sdata->local;
+       struct cfg80211_bss *cbss;
+       struct ieee80211_bss *bss;
+       struct ieee80211_channel *channel;
+       u64 beacon_timestamp, rx_timestamp;
+       u32 supp_rates = 0;
+       enum ieee80211_band band = rx_status->band;
+       channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
+       if (!channel)
+               return;
+       ieee80211_update_sta_info(sdata, mgmt, len, rx_status, elems, channel);
        bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
                                        channel);
        if (!bss)
@@@ -1273,7 -1301,7 +1301,7 @@@ static void ieee80211_sta_merge_ibss(st
  
        scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
        ieee80211_request_ibss_scan(sdata, ifibss->ssid, ifibss->ssid_len,
-                                   NULL, scan_width);
+                                   NULL, 0, scan_width);
  }
  
  static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
  
        if (ifibss->privacy)
                capability |= WLAN_CAPABILITY_PRIVACY;
-       else
-               sdata->drop_unencrypted = 0;
  
        __ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
                                  &ifibss->chandef, ifibss->basic_rates,
                                  capability, 0, true);
  }
  
+ static unsigned ibss_setup_channels(struct wiphy *wiphy,
+                                   struct ieee80211_channel **channels,
+                                   unsigned int channels_max,
+                                   u32 center_freq, u32 width)
+ {
+       struct ieee80211_channel *chan = NULL;
+       unsigned int n_chan = 0;
+       u32 start_freq, end_freq, freq;
+       if (width <= 20) {
+               start_freq = center_freq;
+               end_freq = center_freq;
+       } else {
+               start_freq = center_freq - width / 2 + 10;
+               end_freq = center_freq + width / 2 - 10;
+       }
+       for (freq = start_freq; freq <= end_freq; freq += 20) {
+               chan = ieee80211_get_channel(wiphy, freq);
+               if (!chan)
+                       continue;
+               if (n_chan >= channels_max)
+                       return n_chan;
+               channels[n_chan] = chan;
+               n_chan++;
+       }
+       return n_chan;
+ }
+ static unsigned int
+ ieee80211_ibss_setup_scan_channels(struct wiphy *wiphy,
+                                  const struct cfg80211_chan_def *chandef,
+                                  struct ieee80211_channel **channels,
+                                  unsigned int channels_max)
+ {
+       unsigned int n_chan = 0;
+       u32 width, cf1, cf2 = 0;
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_40:
+               width = 40;
+               break;
+       case NL80211_CHAN_WIDTH_80P80:
+               cf2 = chandef->center_freq2;
+               /* fall through */
+       case NL80211_CHAN_WIDTH_80:
+               width = 80;
+               break;
+       case NL80211_CHAN_WIDTH_160:
+               width = 160;
+               break;
+       default:
+               width = 20;
+               break;
+       }
+       cf1 = chandef->center_freq1;
+       n_chan = ibss_setup_channels(wiphy, channels, channels_max, cf1, width);
+       if (cf2)
+               n_chan += ibss_setup_channels(wiphy, &channels[n_chan],
+                                             channels_max - n_chan, cf2,
+                                             width);
+       return n_chan;
+ }
  /*
   * This function is called with state == IEEE80211_IBSS_MLME_SEARCH
   */
@@@ -1325,7 -1421,6 +1421,6 @@@ static void ieee80211_sta_find_ibss(str
        const u8 *bssid = NULL;
        enum nl80211_bss_scan_width scan_width;
        int active_ibss;
-       u16 capability;
  
        sdata_assert_lock(sdata);
  
        if (active_ibss)
                return;
  
-       capability = WLAN_CAPABILITY_IBSS;
-       if (ifibss->privacy)
-               capability |= WLAN_CAPABILITY_PRIVACY;
        if (ifibss->fixed_bssid)
                bssid = ifibss->bssid;
        if (ifibss->fixed_channel)
                bssid = ifibss->bssid;
        cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid,
                                ifibss->ssid, ifibss->ssid_len,
-                               WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY,
-                               capability);
+                               IEEE80211_BSS_TYPE_IBSS,
+                               IEEE80211_PRIVACY(ifibss->privacy));
  
        if (cbss) {
                struct ieee80211_bss *bss;
        /* Selected IBSS not found in current scan results - try to scan */
        if (time_after(jiffies, ifibss->last_scan_completed +
                                        IEEE80211_SCAN_INTERVAL)) {
+               struct ieee80211_channel *channels[8];
+               unsigned int num;
                sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
  
+               num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
+                                                        &ifibss->chandef,
+                                                        channels,
+                                                        ARRAY_SIZE(channels));
                scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
                ieee80211_request_ibss_scan(sdata, ifibss->ssid,
-                                           ifibss->ssid_len, chan,
+                                           ifibss->ssid_len, channels, num,
                                            scan_width);
        } else {
                int interval = IEEE80211_SCAN_INTERVAL;
@@@ -1742,7 -1841,7 +1841,7 @@@ int ieee80211_ibss_leave(struct ieee802
  
        ieee80211_ibss_disconnect(sdata);
        ifibss->ssid_len = 0;
 -      memset(ifibss->bssid, 0, ETH_ALEN);
 +      eth_zero_addr(ifibss->bssid);
  
        /* remove beacon */
        kfree(sdata->u.ibss.ie);
@@@ -58,24 -58,13 +58,24 @@@ struct ieee80211_local
  #define IEEE80211_UNSET_POWER_LEVEL   INT_MIN
  
  /*
 - * Some APs experience problems when working with U-APSD. Decrease the
 - * probability of that happening by using legacy mode for all ACs but VO.
 - * The AP that caused us trouble was a Cisco 4410N. It ignores our
 - * setting, and always treats non-VO ACs as legacy.
 + * Some APs experience problems when working with U-APSD. Decreasing the
 + * probability of that happening by using legacy mode for all ACs but VO isn't
 + * enough.
 + *
 + * Cisco 4410N originally forced us to enable VO by default only because it
 + * treated non-VO ACs as legacy.
 + *
 + * However some APs (notably Netgear R7000) silently reclassify packets to
 + * different ACs. Since u-APSD ACs require trigger frames for frame retrieval
 + * clients would never see some frames (e.g. ARP responses) or would fetch them
 + * accidentally after a long time.
 + *
 + * It makes little sense to enable u-APSD queues by default because it needs
 + * userspace applications to be aware of it to actually take advantage of the
 + * possible additional powersavings. Implicitly depending on driver autotrigger
 + * frame support doesn't make much sense.
   */
 -#define IEEE80211_DEFAULT_UAPSD_QUEUES \
 -      IEEE80211_WMM_IE_STA_QOSINFO_AC_VO
 +#define IEEE80211_DEFAULT_UAPSD_QUEUES 0
  
  #define IEEE80211_DEFAULT_MAX_SP_LEN          \
        IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL
@@@ -464,7 -453,6 +464,7 @@@ struct ieee80211_if_managed 
        unsigned int flags;
  
        bool csa_waiting_bcn;
 +      bool csa_ignored_same_chan;
  
        bool beacon_crc_valid;
        u32 beacon_crc;
@@@ -830,8 -818,6 +830,6 @@@ struct ieee80211_sub_if_data 
  
        unsigned long state;
  
-       int drop_unencrypted;
        char name[IFNAMSIZ];
  
        /* Fragment table for host-based reassembly */
@@@ -1042,24 -1028,6 +1040,6 @@@ struct tpt_led_trigger 
  };
  #endif
  
- /*
-  * struct ieee80211_tx_latency_bin_ranges - Tx latency statistics bins ranges
-  *
-  * Measuring Tx latency statistics. Counts how many Tx frames transmitted in a
-  * certain latency range (in Milliseconds). Each station that uses these
-  * ranges will have bins to count the amount of frames received in that range.
-  * The user can configure the ranges via debugfs.
-  * If ranges is NULL then Tx latency statistics bins are disabled for all
-  * stations.
-  *
-  * @n_ranges: number of ranges that are taken in account
-  * @ranges: the ranges that the user requested or NULL if disabled.
-  */
- struct ieee80211_tx_latency_bin_ranges {
-       int n_ranges;
-       u32 ranges[];
- };
  /**
   * mac80211 scan flags - currently active scan mode
   *
@@@ -1211,12 -1179,6 +1191,6 @@@ struct ieee80211_local 
        struct timer_list sta_cleanup;
        int sta_generation;
  
-       /*
-        * Tx latency statistics parameters for all stations.
-        * Can enable via debugfs (NULL when disabled).
-        */
-       struct ieee80211_tx_latency_bin_ranges __rcu *tx_latency;
        struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
        struct tasklet_struct tx_pending_tasklet;
  
        /* TX/RX handler statistics */
        unsigned int tx_handlers_drop;
        unsigned int tx_handlers_queued;
-       unsigned int tx_handlers_drop_unencrypted;
        unsigned int tx_handlers_drop_fragment;
        unsigned int tx_handlers_drop_wep;
        unsigned int tx_handlers_drop_not_assoc;
@@@ -1568,7 -1529,8 +1541,8 @@@ int ieee80211_mesh_finish_csa(struct ie
  void ieee80211_scan_work(struct work_struct *work);
  int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata,
                                const u8 *ssid, u8 ssid_len,
-                               struct ieee80211_channel *chan,
+                               struct ieee80211_channel **channels,
+                               unsigned int n_channels,
                                enum nl80211_bss_scan_width scan_width);
  int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
                           struct cfg80211_scan_request *req);
@@@ -1617,6 -1579,7 +1591,7 @@@ int ieee80211_channel_switch(struct wip
  int ieee80211_iface_init(void);
  void ieee80211_iface_exit(void);
  int ieee80211_if_add(struct ieee80211_local *local, const char *name,
+                    unsigned char name_assign_type,
                     struct wireless_dev **new_wdev, enum nl80211_iftype type,
                     struct vif_params *params);
  int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
@@@ -1784,7 -1747,8 +1759,8 @@@ void mac80211_ev_michael_mic_failure(st
                                     gfp_t gfp);
  void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
                               bool bss_notify);
- void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
+ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
+                   struct sta_info *sta, struct sk_buff *skb);
  
  void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
                                 struct sk_buff *skb, int tid,
@@@ -1979,6 -1943,8 +1955,8 @@@ u8 *ieee80211_ie_build_ht_oper(u8 *pos
                               u16 prot_mode);
  u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
                               u32 cap);
+ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
+                               const struct cfg80211_chan_def *chandef);
  int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
                             const struct ieee80211_supported_band *sband,
                             const u8 *srates, int srates_len, u32 *rates);
@@@ -1994,6 -1960,9 +1972,9 @@@ u8 *ieee80211_add_wmm_info_ie(u8 *buf, 
  void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
                                  const struct ieee80211_ht_operation *ht_oper,
                                  struct cfg80211_chan_def *chandef);
+ void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
+                                  const struct ieee80211_vht_operation *oper,
+                                  struct cfg80211_chan_def *chandef);
  u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
  
  int __must_check
diff --combined net/mac80211/mesh.c
@@@ -520,7 -520,7 +520,7 @@@ int ieee80211_fill_mesh_addresses(struc
        } else {
                *fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                /* RA TA DA SA */
 -              memset(hdr->addr1, 0, ETH_ALEN);   /* RA is resolved later */
 +              eth_zero_addr(hdr->addr1);   /* RA is resolved later */
                memcpy(hdr->addr2, meshsa, ETH_ALEN);
                memcpy(hdr->addr3, meshda, ETH_ALEN);
                memcpy(hdr->addr4, meshsa, ETH_ALEN);
@@@ -574,7 -574,8 +574,8 @@@ static void ieee80211_mesh_housekeeping
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        u32 changed;
  
-       ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ);
+       if (ifmsh->mshcfg.plink_timeout > 0)
+               ieee80211_sta_expire(sdata, ifmsh->mshcfg.plink_timeout * HZ);
        mesh_path_expire(sdata);
  
        changed = mesh_accept_plinks_update(sdata);
diff --combined net/mac80211/mlme.c
@@@ -1150,17 -1150,6 +1150,17 @@@ ieee80211_sta_process_chanswitch(struc
                return;
        }
  
 +      if (cfg80211_chandef_identical(&csa_ie.chandef,
 +                                     &sdata->vif.bss_conf.chandef)) {
 +              if (ifmgd->csa_ignored_same_chan)
 +                      return;
 +              sdata_info(sdata,
 +                         "AP %pM tries to chanswitch to same channel, ignore\n",
 +                         ifmgd->associated->bssid);
 +              ifmgd->csa_ignored_same_chan = true;
 +              return;
 +      }
 +
        mutex_lock(&local->mtx);
        mutex_lock(&local->chanctx_mtx);
        conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
        if (!conf) {
                sdata_info(sdata,
                           "no channel context assigned to vif?, disconnecting\n");
-               ieee80211_queue_work(&local->hw,
-                                    &ifmgd->csa_connection_drop_work);
-               mutex_unlock(&local->chanctx_mtx);
-               mutex_unlock(&local->mtx);
-               return;
+               goto drop_connection;
        }
  
        chanctx = container_of(conf, struct ieee80211_chanctx, conf);
            !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
                sdata_info(sdata,
                           "driver doesn't support chan-switch with channel contexts\n");
-               ieee80211_queue_work(&local->hw,
-                                    &ifmgd->csa_connection_drop_work);
-               mutex_unlock(&local->chanctx_mtx);
-               mutex_unlock(&local->mtx);
-               return;
+               goto drop_connection;
        }
  
        ch_switch.timestamp = timestamp;
        if (drv_pre_channel_switch(sdata, &ch_switch)) {
                sdata_info(sdata,
                           "preparing for channel switch failed, disconnecting\n");
-               ieee80211_queue_work(&local->hw,
-                                    &ifmgd->csa_connection_drop_work);
-               mutex_unlock(&local->chanctx_mtx);
-               mutex_unlock(&local->mtx);
-               return;
+               goto drop_connection;
        }
  
        res = ieee80211_vif_reserve_chanctx(sdata, &csa_ie.chandef,
                sdata_info(sdata,
                           "failed to reserve channel context for channel switch, disconnecting (err=%d)\n",
                           res);
-               ieee80211_queue_work(&local->hw,
-                                    &ifmgd->csa_connection_drop_work);
-               mutex_unlock(&local->chanctx_mtx);
-               mutex_unlock(&local->mtx);
-               return;
+               goto drop_connection;
        }
        mutex_unlock(&local->chanctx_mtx);
  
        sdata->vif.csa_active = true;
        sdata->csa_chandef = csa_ie.chandef;
        sdata->csa_block_tx = csa_ie.mode;
 +      ifmgd->csa_ignored_same_chan = false;
  
        if (sdata->csa_block_tx)
                ieee80211_stop_vif_queues(local, sdata,
                mod_timer(&ifmgd->chswitch_timer,
                          TU_TO_EXP_TIME((csa_ie.count - 1) *
                                         cbss->beacon_interval));
+       return;
+  drop_connection:
+       ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work);
+       mutex_unlock(&local->chanctx_mtx);
+       mutex_unlock(&local->mtx);
  }
  
  static bool
@@@ -1633,9 -1610,6 +1622,6 @@@ void ieee80211_dynamic_ps_timer(unsigne
  {
        struct ieee80211_local *local = (void *) data;
  
-       if (local->quiescing || local->suspended)
-               return;
        ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work);
  }
  
@@@ -2045,7 -2019,7 +2031,7 @@@ static void ieee80211_set_disassoc(stru
                ieee80211_flush_queues(local, sdata, false);
  
        /* clear bssid only after building the needed mgmt frames */
 -      memset(ifmgd->bssid, 0, ETH_ALEN);
 +      eth_zero_addr(ifmgd->bssid);
  
        /* remove AP and TDLS peers */
        sta_info_flush(sdata);
  
        sdata->vif.csa_active = false;
        ifmgd->csa_waiting_bcn = false;
 +      ifmgd->csa_ignored_same_chan = false;
        if (sdata->csa_block_tx) {
                ieee80211_wake_vif_queues(local, sdata,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
@@@ -2260,7 -2233,7 +2246,7 @@@ static void ieee80211_mgd_probe_ap_send
                else
                        ssid_len = ssid[1];
  
-               ieee80211_send_probe_req(sdata, sdata->vif.addr, NULL,
+               ieee80211_send_probe_req(sdata, sdata->vif.addr, dst,
                                         ssid + 2, ssid_len, NULL,
                                         0, (u32) -1, true, 0,
                                         ifmgd->associated->channel, false);
@@@ -2372,6 -2345,24 +2358,24 @@@ struct sk_buff *ieee80211_ap_probereq_g
  }
  EXPORT_SYMBOL(ieee80211_ap_probereq_get);
  
+ static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata,
+                                       const u8 *buf, size_t len, bool tx,
+                                       u16 reason)
+ {
+       struct ieee80211_event event = {
+               .type = MLME_EVENT,
+               .u.mlme.data = tx ? DEAUTH_TX_EVENT : DEAUTH_RX_EVENT,
+               .u.mlme.reason = reason,
+       };
+       if (tx)
+               cfg80211_tx_mlme_mgmt(sdata->dev, buf, len);
+       else
+               cfg80211_rx_mlme_mgmt(sdata->dev, buf, len);
+       drv_event_callback(sdata->local, sdata, &event);
+ }
  static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
  {
        struct ieee80211_local *local = sdata->local;
        }
        mutex_unlock(&local->mtx);
  
-       cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
-                             IEEE80211_DEAUTH_FRAME_LEN);
+       ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
+                                   WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
        sdata_unlock(sdata);
  }
  
@@@ -2477,7 -2469,7 +2482,7 @@@ static void ieee80211_destroy_auth_data
                del_timer_sync(&sdata->u.mgd.timer);
                sta_info_destroy_addr(sdata, auth_data->bss->bssid);
  
 -              memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
 +              eth_zero_addr(sdata->u.mgd.bssid);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
                sdata->u.mgd.flags = 0;
                mutex_lock(&sdata->local->mtx);
@@@ -2522,6 -2514,10 +2527,10 @@@ static void ieee80211_rx_mgmt_auth(stru
        u8 bssid[ETH_ALEN];
        u16 auth_alg, auth_transaction, status_code;
        struct sta_info *sta;
+       struct ieee80211_event event = {
+               .type = MLME_EVENT,
+               .u.mlme.data = AUTH_EVENT,
+       };
  
        sdata_assert_lock(sdata);
  
                           mgmt->sa, status_code);
                ieee80211_destroy_auth_data(sdata, false);
                cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
+               event.u.mlme.status = MLME_DENIED;
+               event.u.mlme.reason = status_code;
+               drv_event_callback(sdata->local, sdata, &event);
                return;
        }
  
                return;
        }
  
+       event.u.mlme.status = MLME_SUCCESS;
+       drv_event_callback(sdata->local, sdata, &event);
        sdata_info(sdata, "authenticated\n");
        ifmgd->auth_data->done = true;
        ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
@@@ -2694,7 -2695,7 +2708,7 @@@ static void ieee80211_rx_mgmt_deauth(st
  
        ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
  
-       cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
+       ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code);
  }
  
  
@@@ -2720,7 -2721,7 +2734,7 @@@ static void ieee80211_rx_mgmt_disassoc(
  
        ieee80211_set_disassoc(sdata, 0, 0, false, NULL);
  
-       cfg80211_rx_mlme_mgmt(sdata->dev, (u8 *)mgmt, len);
+       ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code);
  }
  
  static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
@@@ -2790,7 -2791,7 +2804,7 @@@ static void ieee80211_destroy_assoc_dat
                del_timer_sync(&sdata->u.mgd.timer);
                sta_info_destroy_addr(sdata, assoc_data->bss->bssid);
  
 -              memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
 +              eth_zero_addr(sdata->u.mgd.bssid);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
                sdata->u.mgd.flags = 0;
                mutex_lock(&sdata->local->mtx);
@@@ -2982,10 -2983,14 +2996,14 @@@ static bool ieee80211_assoc_success(str
  
        rate_control_rate_init(sta);
  
-       if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
+       if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) {
                set_sta_flag(sta, WLAN_STA_MFP);
+               sta->sta.mfp = true;
+       } else {
+               sta->sta.mfp = false;
+       }
  
-       sta->sta.wme = elems.wmm_param;
+       sta->sta.wme = elems.wmm_param && local->hw.queues >= IEEE80211_NUM_ACS;
  
        err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
        if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
@@@ -3055,6 -3060,10 +3073,10 @@@ static void ieee80211_rx_mgmt_assoc_res
        u8 *pos;
        bool reassoc;
        struct cfg80211_bss *bss;
+       struct ieee80211_event event = {
+               .type = MLME_EVENT,
+               .u.mlme.data = ASSOC_EVENT,
+       };
  
        sdata_assert_lock(sdata);
  
                sdata_info(sdata, "%pM denied association (code=%d)\n",
                           mgmt->sa, status_code);
                ieee80211_destroy_assoc_data(sdata, false);
+               event.u.mlme.status = MLME_DENIED;
+               event.u.mlme.reason = status_code;
+               drv_event_callback(sdata->local, sdata, &event);
        } else {
                if (!ieee80211_assoc_success(sdata, bss, mgmt, len)) {
                        /* oops -- internal error -- send timeout for now */
                        cfg80211_assoc_timeout(sdata->dev, bss);
                        return;
                }
+               event.u.mlme.status = MLME_SUCCESS;
+               drv_event_callback(sdata->local, sdata, &event);
                sdata_info(sdata, "associated\n");
  
                /*
@@@ -3217,8 -3231,7 +3244,8 @@@ static const u64 care_about_ies 
        (1ULL << WLAN_EID_CHANNEL_SWITCH) |
        (1ULL << WLAN_EID_PWR_CONSTRAINT) |
        (1ULL << WLAN_EID_HT_CAPABILITY) |
 -      (1ULL << WLAN_EID_HT_OPERATION);
 +      (1ULL << WLAN_EID_HT_OPERATION) |
 +      (1ULL << WLAN_EID_EXT_CHANSWITCH_ANN);
  
  static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_mgmt *mgmt, size_t len,
            ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
                int sig = ifmgd->ave_beacon_signal;
                int last_sig = ifmgd->last_ave_beacon_signal;
+               struct ieee80211_event event = {
+                       .type = RSSI_EVENT,
+               };
  
                /*
                 * if signal crosses either of the boundaries, invoke callback
                if (sig > ifmgd->rssi_max_thold &&
                    (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) {
                        ifmgd->last_ave_beacon_signal = sig;
-                       drv_rssi_callback(local, sdata, RSSI_EVENT_HIGH);
+                       event.u.rssi.data = RSSI_EVENT_HIGH;
+                       drv_event_callback(local, sdata, &event);
                } else if (sig < ifmgd->rssi_min_thold &&
                           (last_sig >= ifmgd->rssi_max_thold ||
                           last_sig == 0)) {
                        ifmgd->last_ave_beacon_signal = sig;
-                       drv_rssi_callback(local, sdata, RSSI_EVENT_LOW);
+                       event.u.rssi.data = RSSI_EVENT_LOW;
+                       drv_event_callback(local, sdata, &event);
                }
        }
  
        if (ifmgd->csa_waiting_bcn)
                ieee80211_chswitch_post_beacon(sdata);
  
+       /*
+        * Update beacon timing and dtim count on every beacon appearance. This
+        * will allow the driver to use the most updated values. Do it before
+        * comparing this one with last received beacon.
+        * IMPORTANT: These parameters would possibly be out of sync by the time
+        * the driver will use them. The synchronized view is currently
+        * guaranteed only in certain callbacks.
+        */
+       if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) {
+               sdata->vif.bss_conf.sync_tsf =
+                       le64_to_cpu(mgmt->u.beacon.timestamp);
+               sdata->vif.bss_conf.sync_device_ts =
+                       rx_status->device_timestamp;
+               if (elems.tim)
+                       sdata->vif.bss_conf.sync_dtim_count =
+                               elems.tim->dtim_count;
+               else
+                       sdata->vif.bss_conf.sync_dtim_count = 0;
+       }
        if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
                return;
        ifmgd->beacon_crc = ncrc;
                else
                        bss_conf->dtim_period = 1;
  
-               if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) {
-                       sdata->vif.bss_conf.sync_tsf =
-                               le64_to_cpu(mgmt->u.beacon.timestamp);
-                       sdata->vif.bss_conf.sync_device_ts =
-                               rx_status->device_timestamp;
-                       if (elems.tim)
-                               sdata->vif.bss_conf.sync_dtim_count =
-                                       elems.tim->dtim_count;
-                       else
-                               sdata->vif.bss_conf.sync_dtim_count = 0;
-               }
                changed |= BSS_CHANGED_BEACON_INFO;
                ifmgd->have_beacon = true;
  
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                       WLAN_REASON_DEAUTH_LEAVING,
                                       true, deauth_buf);
-               cfg80211_tx_mlme_mgmt(sdata->dev, deauth_buf,
-                                     sizeof(deauth_buf));
+               ieee80211_report_disconnect(sdata, deauth_buf,
+                                           sizeof(deauth_buf), true,
+                                           WLAN_REASON_DEAUTH_LEAVING);
                return;
        }
  
@@@ -3621,8 -3648,8 +3662,8 @@@ static void ieee80211_sta_connection_lo
        ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason,
                               tx, frame_buf);
  
-       cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
-                             IEEE80211_DEAUTH_FRAME_LEN);
+       ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
+                                   reason);
  }
  
  static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
@@@ -3816,12 -3843,18 +3857,18 @@@ void ieee80211_sta_work(struct ieee8021
                        ieee80211_destroy_auth_data(sdata, false);
                } else if (ieee80211_probe_auth(sdata)) {
                        u8 bssid[ETH_ALEN];
+                       struct ieee80211_event event = {
+                               .type = MLME_EVENT,
+                               .u.mlme.data = AUTH_EVENT,
+                               .u.mlme.status = MLME_TIMEOUT,
+                       };
  
                        memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN);
  
                        ieee80211_destroy_auth_data(sdata, false);
  
                        cfg80211_auth_timeout(sdata->dev, bssid);
+                       drv_event_callback(sdata->local, sdata, &event);
                }
        } else if (ifmgd->auth_data && ifmgd->auth_data->timeout_started)
                run_again(sdata, ifmgd->auth_data->timeout);
                if ((ifmgd->assoc_data->need_beacon && !ifmgd->have_beacon) ||
                    ieee80211_do_assoc(sdata)) {
                        struct cfg80211_bss *bss = ifmgd->assoc_data->bss;
+                       struct ieee80211_event event = {
+                               .type = MLME_EVENT,
+                               .u.mlme.data = ASSOC_EVENT,
+                               .u.mlme.status = MLME_TIMEOUT,
+                       };
  
                        ieee80211_destroy_assoc_data(sdata, false);
                        cfg80211_assoc_timeout(sdata->dev, bss);
+                       drv_event_callback(sdata->local, sdata, &event);
                }
        } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)
                run_again(sdata, ifmgd->assoc_data->timeout);
@@@ -3905,12 -3944,8 +3958,8 @@@ static void ieee80211_sta_bcn_mon_timer
  {
        struct ieee80211_sub_if_data *sdata =
                (struct ieee80211_sub_if_data *) data;
-       struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
  
-       if (local->quiescing)
-               return;
        if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
                return;
  
@@@ -3926,9 -3961,6 +3975,6 @@@ static void ieee80211_sta_conn_mon_time
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
  
-       if (local->quiescing)
-               return;
        if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
                return;
  
@@@ -3991,6 -4023,34 +4037,34 @@@ void ieee80211_mgd_quiesce(struct ieee8
                                      IEEE80211_DEAUTH_FRAME_LEN);
        }
  
+       /* This is a bit of a hack - we should find a better and more generic
+        * solution to this. Normally when suspending, cfg80211 will in fact
+        * deauthenticate. However, it doesn't (and cannot) stop an ongoing
+        * auth (not so important) or assoc (this is the problem) process.
+        *
+        * As a consequence, it can happen that we are in the process of both
+        * associating and suspending, and receive an association response
+        * after cfg80211 has checked if it needs to disconnect, but before
+        * we actually set the flag to drop incoming frames. This will then
+        * cause the workqueue flush to process the association response in
+        * the suspend, resulting in a successful association just before it
+        * tries to remove the interface from the driver, which now though
+        * has a channel context assigned ... this results in issues.
+        *
+        * To work around this (for now) simply deauth here again if we're
+        * now connected.
+        */
+       if (ifmgd->associated && !sdata->local->wowlan) {
+               u8 bssid[ETH_ALEN];
+               struct cfg80211_deauth_request req = {
+                       .reason_code = WLAN_REASON_DEAUTH_LEAVING,
+                       .bssid = bssid,
+               };
+               memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
+               ieee80211_mgd_deauth(sdata, &req);
+       }
        sdata_unlock(sdata);
  }
  
@@@ -4379,6 -4439,10 +4453,10 @@@ static int ieee80211_prep_connection(st
        } else
                WARN_ON_ONCE(!ether_addr_equal(ifmgd->bssid, cbss->bssid));
  
+       /* Cancel scan to ensure that nothing interferes with connection */
+       if (local->scanning)
+               ieee80211_scan_cancel(local);
        return 0;
  }
  
@@@ -4467,8 -4531,9 +4545,9 @@@ int ieee80211_mgd_auth(struct ieee80211
                                       WLAN_REASON_UNSPECIFIED,
                                       false, frame_buf);
  
-               cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
-                                     sizeof(frame_buf));
+               ieee80211_report_disconnect(sdata, frame_buf,
+                                           sizeof(frame_buf), true,
+                                           WLAN_REASON_UNSPECIFIED);
        }
  
        sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
        return 0;
  
   err_clear:
 -      memset(ifmgd->bssid, 0, ETH_ALEN);
 +      eth_zero_addr(ifmgd->bssid);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
        ifmgd->auth_data = NULL;
   err_free:
@@@ -4568,8 -4633,9 +4647,9 @@@ int ieee80211_mgd_assoc(struct ieee8021
                                       WLAN_REASON_UNSPECIFIED,
                                       false, frame_buf);
  
-               cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
-                                     sizeof(frame_buf));
+               ieee80211_report_disconnect(sdata, frame_buf,
+                                           sizeof(frame_buf), true,
+                                           WLAN_REASON_UNSPECIFIED);
        }
  
        if (ifmgd->auth_data && !ifmgd->auth_data->done) {
  
        return 0;
   err_clear:
 -      memset(ifmgd->bssid, 0, ETH_ALEN);
 +      eth_zero_addr(ifmgd->bssid);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
        ifmgd->assoc_data = NULL;
   err_free:
@@@ -4859,8 -4925,9 +4939,9 @@@ int ieee80211_mgd_deauth(struct ieee802
                                               req->reason_code, tx,
                                               frame_buf);
                ieee80211_destroy_auth_data(sdata, false);
-               cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
-                                     IEEE80211_DEAUTH_FRAME_LEN);
+               ieee80211_report_disconnect(sdata, frame_buf,
+                                           sizeof(frame_buf), true,
+                                           req->reason_code);
  
                return 0;
        }
  
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                       req->reason_code, tx, frame_buf);
-               cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
-                                     IEEE80211_DEAUTH_FRAME_LEN);
+               ieee80211_report_disconnect(sdata, frame_buf,
+                                           sizeof(frame_buf), true,
+                                           req->reason_code);
                return 0;
        }
  
@@@ -4907,8 -4975,8 +4989,8 @@@ int ieee80211_mgd_disassoc(struct ieee8
                               req->reason_code, !req->local_state_change,
                               frame_buf);
  
-       cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf,
-                             IEEE80211_DEAUTH_FRAME_LEN);
+       ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
+                                   req->reason_code);
  
        return 0;
  }
diff --combined net/mac80211/rx.c
@@@ -1912,8 -1912,7 +1912,7 @@@ static int ieee80211_drop_unencrypted(s
        /* Drop unencrypted frames if key is set. */
        if (unlikely(!ieee80211_has_protected(fc) &&
                     !ieee80211_is_nullfunc(fc) &&
-                    ieee80211_is_data(fc) &&
-                    (rx->key || rx->sdata->drop_unencrypted)))
+                    ieee80211_is_data(fc) && rx->key))
                return -EACCES;
  
        return 0;
@@@ -2043,6 -2042,9 +2042,9 @@@ ieee80211_deliver_skb(struct ieee80211_
        struct sta_info *dsta;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
  
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += rx->skb->len;
        skb = rx->skb;
        xmit_skb = NULL;
  
@@@ -2173,8 -2175,6 +2175,6 @@@ ieee80211_rx_h_amsdu(struct ieee80211_r
                        dev_kfree_skb(rx->skb);
                        continue;
                }
-               dev->stats.rx_packets++;
-               dev->stats.rx_bytes += rx->skb->len;
  
                ieee80211_deliver_skb(rx);
        }
@@@ -2214,9 -2214,6 +2214,9 @@@ ieee80211_rx_h_mesh_fwding(struct ieee8
        hdr = (struct ieee80211_hdr *) skb->data;
        mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
  
 +      if (ieee80211_drop_unencrypted(rx, hdr->frame_control))
 +              return RX_DROP_MONITOR;
 +
        /* frame is in RMC, don't forward */
        if (ieee80211_is_data(hdr->frame_control) &&
            is_multicast_ether_addr(hdr->addr1) &&
@@@ -2400,9 -2397,6 +2400,6 @@@ ieee80211_rx_h_data(struct ieee80211_rx
  
        rx->skb->dev = dev;
  
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += rx->skb->len;
        if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
            !is_multicast_ether_addr(
                    ((struct ethhdr *)rx->skb->data)->h_dest) &&
@@@ -3128,6 -3122,12 +3125,12 @@@ static void ieee80211_rx_handlers(struc
                        goto rxh_next;  \
        } while (0);
  
+       /* Lock here to avoid hitting all of the data used in the RX
+        * path (e.g. key data, station data, ...) concurrently when
+        * a frame is released from the reorder buffer due to timeout
+        * from the timer, potentially concurrently with RX from the
+        * driver.
+        */
        spin_lock_bh(&rx->local->rx_path_lock);
  
        while ((skb = __skb_dequeue(frames))) {
diff --combined net/mac80211/tx.c
@@@ -20,7 -20,6 +20,6 @@@
  #include <linux/bitmap.h>
  #include <linux/rcupdate.h>
  #include <linux/export.h>
- #include <linux/time.h>
  #include <net/net_namespace.h>
  #include <net/ieee80211_radiotap.h>
  #include <net/cfg80211.h>
@@@ -566,7 -565,6 +565,7 @@@ ieee80211_tx_h_check_control_port_proto
                if (tx->sdata->control_port_no_encrypt)
                        info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
                info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
 +              info->flags |= IEEE80211_TX_CTL_USE_MINRATE;
        }
  
        return TX_CONTINUE;
@@@ -595,23 -593,8 +594,8 @@@ ieee80211_tx_h_select_key(struct ieee80
        else if (!is_multicast_ether_addr(hdr->addr1) &&
                 (key = rcu_dereference(tx->sdata->default_unicast_key)))
                tx->key = key;
-       else if (info->flags & IEEE80211_TX_CTL_INJECTED)
-               tx->key = NULL;
-       else if (!tx->sdata->drop_unencrypted)
-               tx->key = NULL;
-       else if (tx->skb->protocol == tx->sdata->control_port_protocol)
-               tx->key = NULL;
-       else if (ieee80211_is_robust_mgmt_frame(tx->skb) &&
-                !(ieee80211_is_action(hdr->frame_control) &&
-                  tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))
-               tx->key = NULL;
-       else if (ieee80211_is_mgmt(hdr->frame_control) &&
-                !ieee80211_is_robust_mgmt_frame(tx->skb))
+       else
                tx->key = NULL;
-       else {
-               I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
-               return TX_DROP;
-       }
  
        if (tx->key) {
                bool skip_hw = false;
@@@ -1137,11 -1120,13 +1121,13 @@@ static bool ieee80211_tx_prep_agg(struc
  
  /*
   * initialises @tx
+  * pass %NULL for the station if unknown, a valid pointer if known
+  * or an ERR_PTR() if the station is known not to exist
   */
  static ieee80211_tx_result
  ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
                     struct ieee80211_tx_data *tx,
-                    struct sk_buff *skb)
+                    struct sta_info *sta, struct sk_buff *skb)
  {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_hdr *hdr;
  
        hdr = (struct ieee80211_hdr *) skb->data;
  
-       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
-               tx->sta = rcu_dereference(sdata->u.vlan.sta);
-               if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr)
-                       return TX_DROP;
-       } else if (info->flags & (IEEE80211_TX_CTL_INJECTED |
-                                 IEEE80211_TX_INTFL_NL80211_FRAME_TX) ||
-                  tx->sdata->control_port_protocol == tx->skb->protocol) {
-               tx->sta = sta_info_get_bss(sdata, hdr->addr1);
+       if (likely(sta)) {
+               if (!IS_ERR(sta))
+                       tx->sta = sta;
+       } else {
+               if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+                       tx->sta = rcu_dereference(sdata->u.vlan.sta);
+                       if (!tx->sta && sdata->wdev.use_4addr)
+                               return TX_DROP;
+               } else if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+                                         IEEE80211_TX_CTL_INJECTED) ||
+                          tx->sdata->control_port_protocol == tx->skb->protocol) {
+                       tx->sta = sta_info_get_bss(sdata, hdr->addr1);
+               }
+               if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
+                       tx->sta = sta_info_get(sdata, hdr->addr1);
        }
-       if (!tx->sta)
-               tx->sta = sta_info_get(sdata, hdr->addr1);
  
        if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
            !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
@@@ -1422,8 -1412,9 +1413,9 @@@ bool ieee80211_tx_prepare_skb(struct ie
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_tx_data tx;
+       struct sk_buff *skb2;
  
-       if (ieee80211_tx_prepare(sdata, &tx, skb) == TX_DROP)
+       if (ieee80211_tx_prepare(sdata, &tx, NULL, skb) == TX_DROP)
                return false;
  
        info->band = band;
                        *sta = NULL;
        }
  
+       /* this function isn't suitable for fragmented data frames */
+       skb2 = __skb_dequeue(&tx.skbs);
+       if (WARN_ON(skb2 != skb || !skb_queue_empty(&tx.skbs))) {
+               ieee80211_free_txskb(hw, skb2);
+               ieee80211_purge_tx_queue(hw, &tx.skbs);
+               return false;
+       }
        return true;
  }
  EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
   * Returns false if the frame couldn't be transmitted but was queued instead.
   */
  static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
-                        struct sk_buff *skb, bool txpending)
+                        struct sta_info *sta, struct sk_buff *skb,
+                        bool txpending)
  {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_data tx;
  
        /* initialises tx */
        led_len = skb->len;
-       res_prepare = ieee80211_tx_prepare(sdata, &tx, skb);
+       res_prepare = ieee80211_tx_prepare(sdata, &tx, sta, skb);
  
        if (unlikely(res_prepare == TX_DROP)) {
                ieee80211_free_txskb(&local->hw, skb);
@@@ -1520,7 -1520,8 +1521,8 @@@ static int ieee80211_skb_resize(struct 
        return 0;
  }
  
- void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
+ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
+                   struct sta_info *sta, struct sk_buff *skb)
  {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        }
  
        ieee80211_set_qos_hdr(sdata, skb);
-       ieee80211_tx(sdata, skb, false);
+       ieee80211_tx(sdata, sta, skb, false);
  }
  
  static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
@@@ -1776,7 -1777,7 +1778,7 @@@ netdev_tx_t ieee80211_monitor_start_xmi
                goto fail_rcu;
  
        info->band = chandef->chan->band;
-       ieee80211_xmit(sdata, skb);
+       ieee80211_xmit(sdata, NULL, skb);
        rcu_read_unlock();
  
        return NETDEV_TX_OK;
@@@ -1788,21 -1789,89 +1790,89 @@@ fail
        return NETDEV_TX_OK; /* meaning, we dealt with the skb */
  }
  
- /*
-  * Measure Tx frame arrival time for Tx latency statistics calculation
-  * A single Tx frame latency should be measured from when it is entering the
-  * Kernel until we receive Tx complete confirmation indication and the skb is
-  * freed.
-  */
- static void ieee80211_tx_latency_start_msrmnt(struct ieee80211_local *local,
-                                             struct sk_buff *skb)
+ static inline bool ieee80211_is_tdls_setup(struct sk_buff *skb)
  {
-       struct ieee80211_tx_latency_bin_ranges *tx_latency;
+       u16 ethertype = (skb->data[12] << 8) | skb->data[13];
  
-       tx_latency = rcu_dereference(local->tx_latency);
-       if (!tx_latency)
-               return;
-       skb->tstamp = ktime_get();
+       return ethertype == ETH_P_TDLS &&
+              skb->len > 14 &&
+              skb->data[14] == WLAN_TDLS_SNAP_RFTYPE;
+ }
+ static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata,
+                                  struct sk_buff *skb,
+                                  struct sta_info **sta_out)
+ {
+       struct sta_info *sta;
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_AP_VLAN:
+               sta = rcu_dereference(sdata->u.vlan.sta);
+               if (sta) {
+                       *sta_out = sta;
+                       return 0;
+               } else if (sdata->wdev.use_4addr) {
+                       return -ENOLINK;
+               }
+               /* fall through */
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_OCB:
+       case NL80211_IFTYPE_ADHOC:
+               if (is_multicast_ether_addr(skb->data)) {
+                       *sta_out = ERR_PTR(-ENOENT);
+                       return 0;
+               }
+               sta = sta_info_get_bss(sdata, skb->data);
+               break;
+       case NL80211_IFTYPE_WDS:
+               sta = sta_info_get(sdata, sdata->u.wds.remote_addr);
+               break;
+ #ifdef CONFIG_MAC80211_MESH
+       case NL80211_IFTYPE_MESH_POINT:
+               /* determined much later */
+               *sta_out = NULL;
+               return 0;
+ #endif
+       case NL80211_IFTYPE_STATION:
+               if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
+                       sta = sta_info_get(sdata, skb->data);
+                       if (sta) {
+                               bool tdls_peer, tdls_auth;
+                               tdls_peer = test_sta_flag(sta,
+                                                         WLAN_STA_TDLS_PEER);
+                               tdls_auth = test_sta_flag(sta,
+                                               WLAN_STA_TDLS_PEER_AUTH);
+                               if (tdls_peer && tdls_auth) {
+                                       *sta_out = sta;
+                                       return 0;
+                               }
+                               /*
+                                * TDLS link during setup - throw out frames to
+                                * peer. Allow TDLS-setup frames to unauthorized
+                                * peers for the special case of a link teardown
+                                * after a TDLS sta is removed due to being
+                                * unreachable.
+                                */
+                               if (tdls_peer && !tdls_auth &&
+                                   !ieee80211_is_tdls_setup(skb))
+                                       return -EINVAL;
+                       }
+               }
+               sta = sta_info_get(sdata, sdata->u.mgd.bssid);
+               if (!sta)
+                       return -ENOLINK;
+               break;
+       default:
+               return -EINVAL;
+       }
+       *sta_out = sta ?: ERR_PTR(-ENOENT);
+       return 0;
  }
  
  /**
   * Returns: the (possibly reallocated) skb or an ERR_PTR() code
   */
  static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
-                                          struct sk_buff *skb, u32 info_flags)
+                                          struct sk_buff *skb, u32 info_flags,
+                                          struct sta_info *sta)
  {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_info *info;
        const u8 *encaps_data;
        int encaps_len, skip_header_bytes;
        int nh_pos, h_pos;
-       struct sta_info *sta = NULL;
-       bool wme_sta = false, authorized = false, tdls_auth = false;
-       bool tdls_peer = false, tdls_setup_frame = false;
+       bool wme_sta = false, authorized = false;
+       bool tdls_peer;
        bool multicast;
        u16 info_id = 0;
        struct ieee80211_chanctx_conf *chanctx_conf;
        enum ieee80211_band band;
        int ret;
  
+       if (IS_ERR(sta))
+               sta = NULL;
        /* convert Ethernet header to proper 802.11 header (based on
         * operation mode) */
        ethertype = (skb->data[12] << 8) | skb->data[13];
  
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP_VLAN:
-               sta = rcu_dereference(sdata->u.vlan.sta);
-               if (sta) {
+               if (sdata->wdev.use_4addr) {
                        fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
                        /* RA TA DA SA */
                        memcpy(hdr.addr1, sta->sta.addr, ETH_ALEN);
                        goto free;
                }
                band = chanctx_conf->def.chan->band;
-               if (sta)
+               if (sdata->wdev.use_4addr)
                        break;
                /* fall through */
        case NL80211_IFTYPE_AP:
                break;
  #endif
        case NL80211_IFTYPE_STATION:
-               if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
-                       sta = sta_info_get(sdata, skb->data);
-                       if (sta) {
-                               authorized = test_sta_flag(sta,
-                                                       WLAN_STA_AUTHORIZED);
-                               wme_sta = sta->sta.wme;
-                               tdls_peer = test_sta_flag(sta,
-                                                         WLAN_STA_TDLS_PEER);
-                               tdls_auth = test_sta_flag(sta,
-                                               WLAN_STA_TDLS_PEER_AUTH);
-                       }
-                       if (tdls_peer)
-                               tdls_setup_frame =
-                                       ethertype == ETH_P_TDLS &&
-                                       skb->len > 14 &&
-                                       skb->data[14] == WLAN_TDLS_SNAP_RFTYPE;
-               }
+               /* we already did checks when looking up the RA STA */
+               tdls_peer = test_sta_flag(sta, WLAN_STA_TDLS_PEER);
  
-               /*
-                * TDLS link during setup - throw out frames to peer. We allow
-                * TDLS-setup frames to unauthorized peers for the special case
-                * of a link teardown after a TDLS sta is removed due to being
-                * unreachable.
-                */
-               if (tdls_peer && !tdls_auth && !tdls_setup_frame) {
-                       ret = -EINVAL;
-                       goto free;
-               }
-               /* send direct packets to authorized TDLS peers */
-               if (tdls_peer && tdls_auth) {
+               if (tdls_peer) {
                        /* DA SA BSSID */
                        memcpy(hdr.addr1, skb->data, ETH_ALEN);
                        memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
                goto free;
        }
  
-       /*
-        * There's no need to try to look up the destination
-        * if it is a multicast address (which can only happen
-        * in AP mode)
-        */
        multicast = is_multicast_ether_addr(hdr.addr1);
-       if (!multicast) {
-               sta = sta_info_get(sdata, hdr.addr1);
-               if (sta) {
-                       authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
-                       wme_sta = sta->sta.wme;
-               }
-       }
  
-       /* For mesh, the use of the QoS header is mandatory */
-       if (ieee80211_vif_is_mesh(&sdata->vif))
+       /* sta is always NULL for mesh */
+       if (sta) {
+               authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
+               wme_sta = sta->sta.wme;
+       } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+               /* For mesh, the use of the QoS header is mandatory */
                wme_sta = true;
+       }
  
-       /* receiver and we are QoS enabled, use a QoS type frame */
-       if (wme_sta && local->hw.queues >= IEEE80211_NUM_ACS) {
+       /* receiver does QoS (which also means we do) use it */
+       if (wme_sta) {
                fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
                hdrlen += 2;
        }
@@@ -2260,7 -2296,7 +2297,7 @@@ void __ieee80211_subif_start_xmit(struc
                                  u32 info_flags)
  {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
  
        if (unlikely(skb->len < ETH_HLEN)) {
                kfree_skb(skb);
  
        rcu_read_lock();
  
-       /* Measure frame arrival for Tx latency statistics calculation */
-       ieee80211_tx_latency_start_msrmnt(local, skb);
+       if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
+               kfree_skb(skb);
+               goto out;
+       }
  
-       skb = ieee80211_build_hdr(sdata, skb, info_flags);
+       skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
        if (IS_ERR(skb))
                goto out;
  
        dev->stats.tx_bytes += skb->len;
        dev->trans_start = jiffies;
  
-       ieee80211_xmit(sdata, skb);
+       ieee80211_xmit(sdata, sta, skb);
   out:
        rcu_read_unlock();
  }
@@@ -2308,10 -2346,17 +2347,17 @@@ ieee80211_build_data_template(struct ie
                .local = sdata->local,
                .sdata = sdata,
        };
+       struct sta_info *sta;
  
        rcu_read_lock();
  
-       skb = ieee80211_build_hdr(sdata, skb, info_flags);
+       if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
+               kfree_skb(skb);
+               skb = ERR_PTR(-EINVAL);
+               goto out;
+       }
+       skb = ieee80211_build_hdr(sdata, skb, info_flags, sta);
        if (IS_ERR(skb))
                goto out;
  
@@@ -2369,7 -2414,7 +2415,7 @@@ static bool ieee80211_tx_pending_skb(st
                        return true;
                }
                info->band = chanctx_conf->def.chan->band;
-               result = ieee80211_tx(sdata, skb, true);
+               result = ieee80211_tx(sdata, NULL, skb, true);
        } else {
                struct sk_buff_head skbs;
  
@@@ -3107,7 -3152,7 +3153,7 @@@ ieee80211_get_buffered_bc(struct ieee80
  
                if (sdata->vif.type == NL80211_IFTYPE_AP)
                        sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev);
-               if (!ieee80211_tx_prepare(sdata, &tx, skb))
+               if (!ieee80211_tx_prepare(sdata, &tx, NULL, skb))
                        break;
                dev_kfree_skb_any(skb);
        }
@@@ -3239,6 -3284,6 +3285,6 @@@ void __ieee80211_tx_skb_tid_band(struc
         */
        local_bh_disable();
        IEEE80211_SKB_CB(skb)->band = band;
-       ieee80211_xmit(sdata, skb);
+       ieee80211_xmit(sdata, NULL, skb);
        local_bh_enable();
  }
diff --combined net/mac80211/util.c
@@@ -625,13 -625,14 +625,14 @@@ void ieee80211_wake_vif_queues(struct i
                                        reason, true);
  }
  
- static void __iterate_active_interfaces(struct ieee80211_local *local,
-                                       u32 iter_flags,
-                                       void (*iterator)(void *data, u8 *mac,
-                                               struct ieee80211_vif *vif),
-                                       void *data)
+ static void __iterate_interfaces(struct ieee80211_local *local,
+                                u32 iter_flags,
+                                void (*iterator)(void *data, u8 *mac,
+                                                 struct ieee80211_vif *vif),
+                                void *data)
  {
        struct ieee80211_sub_if_data *sdata;
+       bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE;
  
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                switch (sdata->vif.type) {
                        break;
                }
                if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
-                   !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+                   active_only && !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
                        continue;
-               if (ieee80211_sdata_running(sdata))
+               if (ieee80211_sdata_running(sdata) || !active_only)
                        iterator(data, sdata->vif.addr,
                                 &sdata->vif);
        }
                                      lockdep_is_held(&local->iflist_mtx) ||
                                      lockdep_rtnl_is_held());
        if (sdata &&
-           (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
+           (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL || !active_only ||
             sdata->flags & IEEE80211_SDATA_IN_DRIVER))
                iterator(data, sdata->vif.addr, &sdata->vif);
  }
  
- void ieee80211_iterate_active_interfaces(
+ void ieee80211_iterate_interfaces(
        struct ieee80211_hw *hw, u32 iter_flags,
        void (*iterator)(void *data, u8 *mac,
                         struct ieee80211_vif *vif),
        struct ieee80211_local *local = hw_to_local(hw);
  
        mutex_lock(&local->iflist_mtx);
-       __iterate_active_interfaces(local, iter_flags, iterator, data);
+       __iterate_interfaces(local, iter_flags, iterator, data);
        mutex_unlock(&local->iflist_mtx);
  }
- EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
+ EXPORT_SYMBOL_GPL(ieee80211_iterate_interfaces);
  
  void ieee80211_iterate_active_interfaces_atomic(
        struct ieee80211_hw *hw, u32 iter_flags,
        struct ieee80211_local *local = hw_to_local(hw);
  
        rcu_read_lock();
-       __iterate_active_interfaces(local, iter_flags, iterator, data);
+       __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
+                            iterator, data);
        rcu_read_unlock();
  }
  EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
@@@ -699,7 -701,8 +701,8 @@@ void ieee80211_iterate_active_interface
  
        ASSERT_RTNL();
  
-       __iterate_active_interfaces(local, iter_flags, iterator, data);
+       __iterate_interfaces(local, iter_flags | IEEE80211_IFACE_ITER_ACTIVE,
+                            iterator, data);
  }
  EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
  
@@@ -742,6 -745,18 +745,18 @@@ struct ieee80211_vif *wdev_to_ieee80211
  }
  EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif);
  
+ struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif)
+ {
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       if (!ieee80211_sdata_running(sdata) ||
+           !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+               return NULL;
+       return &sdata->wdev;
+ }
+ EXPORT_SYMBOL_GPL(ieee80211_vif_to_wdev);
  /*
   * Nothing should have been stuffed into the workqueue during
   * the suspend->resume cycle. Since we can't check each caller
@@@ -1811,8 -1826,25 +1826,25 @@@ int ieee80211_reconfig(struct ieee80211
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
-                   ieee80211_sdata_running(sdata))
+                   ieee80211_sdata_running(sdata)) {
                        res = drv_add_interface(local, sdata);
+                       if (WARN_ON(res))
+                               break;
+               }
+       }
+       /* If adding any of the interfaces failed above, roll back and
+        * report failure.
+        */
+       if (res) {
+               list_for_each_entry_continue_reverse(sdata, &local->interfaces,
+                                                    list)
+                       if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+                           sdata->vif.type != NL80211_IFTYPE_MONITOR &&
+                           ieee80211_sdata_running(sdata))
+                               drv_remove_interface(local, sdata);
+               ieee80211_handle_reconfig_failure(local);
+               return res;
        }
  
        /* add channel contexts */
@@@ -2344,6 -2376,41 +2376,41 @@@ u8 *ieee80211_ie_build_ht_oper(u8 *pos
        return pos + sizeof(struct ieee80211_ht_operation);
  }
  
+ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
+                               const struct cfg80211_chan_def *chandef)
+ {
+       struct ieee80211_vht_operation *vht_oper;
+       *pos++ = WLAN_EID_VHT_OPERATION;
+       *pos++ = sizeof(struct ieee80211_vht_operation);
+       vht_oper = (struct ieee80211_vht_operation *)pos;
+       vht_oper->center_freq_seg1_idx = ieee80211_frequency_to_channel(
+                                                       chandef->center_freq1);
+       if (chandef->center_freq2)
+               vht_oper->center_freq_seg2_idx =
+                       ieee80211_frequency_to_channel(chandef->center_freq2);
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_160:
+               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;
+               break;
+       case NL80211_CHAN_WIDTH_80P80:
+               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
+               break;
+       case NL80211_CHAN_WIDTH_80:
+               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
+               break;
+       default:
+               vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_USE_HT;
+               break;
+       }
+       /* don't require special VHT peer rates */
+       vht_oper->basic_mcs_set = cpu_to_le16(0xffff);
+       return pos + sizeof(struct ieee80211_vht_operation);
+ }
  void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
                                  const struct ieee80211_ht_operation *ht_oper,
                                  struct cfg80211_chan_def *chandef)
        cfg80211_chandef_create(chandef, control_chan, channel_type);
  }
  
+ void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
+                                  const struct ieee80211_vht_operation *oper,
+                                  struct cfg80211_chan_def *chandef)
+ {
+       if (!oper)
+               return;
+       chandef->chan = control_chan;
+       switch (oper->chan_width) {
+       case IEEE80211_VHT_CHANWIDTH_USE_HT:
+               break;
+       case IEEE80211_VHT_CHANWIDTH_80MHZ:
+               chandef->width = NL80211_CHAN_WIDTH_80;
+               break;
+       case IEEE80211_VHT_CHANWIDTH_160MHZ:
+               chandef->width = NL80211_CHAN_WIDTH_160;
+               break;
+       case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+               chandef->width = NL80211_CHAN_WIDTH_80P80;
+               break;
+       default:
+               break;
+       }
+       chandef->center_freq1 =
+               ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
+                                              control_chan->band);
+       chandef->center_freq2 =
+               ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
+                                              control_chan->band);
+ }
  int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
                             const struct ieee80211_supported_band *sband,
                             const u8 *srates, int srates_len, u32 *rates)
@@@ -3178,7 -3278,7 +3278,7 @@@ int ieee80211_check_combinations(struc
                wdev_iter = &sdata_iter->wdev;
  
                if (sdata_iter == sdata ||
 -                  rcu_access_pointer(sdata_iter->vif.chanctx_conf) == NULL ||
 +                  !ieee80211_sdata_running(sdata_iter) ||
                    local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
                        continue;
  
diff --combined net/wireless/ibss.c
@@@ -30,7 -30,7 +30,7 @@@ void __cfg80211_ibss_joined(struct net_
                return;
  
        bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0,
-                              WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
+                              IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY);
  
        if (WARN_ON(!bss))
                return;
@@@ -533,7 -533,7 +533,7 @@@ int cfg80211_ibss_wext_giwap(struct net
        else if (wdev->wext.ibss.bssid)
                memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
        else
 -              memset(ap_addr->sa_data, 0, ETH_ALEN);
 +              eth_zero_addr(ap_addr->sa_data);
  
        wdev_unlock(wdev);
  
diff --combined net/wireless/nl80211.c
@@@ -399,6 -399,7 +399,7 @@@ static const struct nla_policy nl80211_
        [NL80211_ATTR_WIPHY_SELF_MANAGED_REG] = { .type = NLA_FLAG },
        [NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
        [NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
+       [NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
  };
  
  /* policy for the key attributes */
@@@ -1098,8 -1099,6 +1099,6 @@@ static int nl80211_send_wowlan(struct s
        if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
                return -ENOBUFS;
  
-       /* TODO: send wowlan net detect */
        nla_nest_end(msg, nl_wowlan);
  
        return 0;
@@@ -2654,6 -2653,10 +2653,6 @@@ static int nl80211_new_interface(struc
                        return err;
        }
  
 -      msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 -      if (!msg)
 -              return -ENOMEM;
 -
        err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
                                  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
                                  &flags);
            !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
                return -EOPNOTSUPP;
  
 +      msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 +      if (!msg)
 +              return -ENOMEM;
 +
        wdev = rdev_add_virtual_intf(rdev,
                                nla_data(info->attrs[NL80211_ATTR_IFNAME]),
-                               type, err ? NULL : &flags, &params);
+                               NET_NAME_USER, type, err ? NULL : &flags,
+                               &params);
        if (WARN_ON(!wdev)) {
                nlmsg_free(msg);
                return -EPROTO;
@@@ -4400,16 -4400,6 +4400,16 @@@ static int nl80211_new_station(struct s
        if (parse_station_flags(info, dev->ieee80211_ptr->iftype, &params))
                return -EINVAL;
  
 +      /* HT/VHT requires QoS, but if we don't have that just ignore HT/VHT
 +       * as userspace might just pass through the capabilities from the IEs
 +       * directly, rather than enforcing this restriction and returning an
 +       * error in this case.
 +       */
 +      if (!(params.sta_flags_set & BIT(NL80211_STA_FLAG_WME))) {
 +              params.ht_capa = NULL;
 +              params.vht_capa = NULL;
 +      }
 +
        /* When you run into this, adjust the code below for the new flag */
        BUILD_BUG_ON(NL80211_STA_FLAG_MAX != 7);
  
@@@ -4968,7 -4958,10 +4968,10 @@@ static int parse_reg_rule(struct nlatt
  static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
  {
        char *data = NULL;
+       bool is_indoor;
        enum nl80211_user_reg_hint_type user_reg_hint_type;
+       u32 owner_nlportid;
  
        /*
         * You should only get this when cfg80211 hasn't yet initialized
                data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]);
                return regulatory_hint_user(data, user_reg_hint_type);
        case NL80211_USER_REG_HINT_INDOOR:
-               return regulatory_hint_indoor_user();
+               if (info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+                       owner_nlportid = info->snd_portid;
+                       is_indoor = !!info->attrs[NL80211_ATTR_REG_INDOOR];
+               } else {
+                       owner_nlportid = 0;
+                       is_indoor = true;
+               }
+               return regulatory_hint_indoor(is_indoor, owner_nlportid);
        default:
                return -EINVAL;
        }
@@@ -5275,7 -5276,7 +5286,7 @@@ do {                                                                        
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshAwakeWindowDuration,
                                  0, 65535, mask,
                                  NL80211_MESHCONF_AWAKE_WINDOW, nla_get_u16);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 1, 0xffffffff,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, plink_timeout, 0, 0xffffffff,
                                  mask, NL80211_MESHCONF_PLINK_TIMEOUT,
                                  nla_get_u32);
        if (mask_out)
@@@ -5693,8 -5694,8 +5704,8 @@@ static int nl80211_parse_random_mac(str
        int i;
  
        if (!attrs[NL80211_ATTR_MAC] && !attrs[NL80211_ATTR_MAC_MASK]) {
 -              memset(mac_addr, 0, ETH_ALEN);
 -              memset(mac_addr_mask, 0, ETH_ALEN);
 +              eth_zero_addr(mac_addr);
 +              eth_zero_addr(mac_addr_mask);
                mac_addr[0] = 0x2;
                mac_addr_mask[0] = 0x3;
  
@@@ -7275,8 -7276,18 +7286,18 @@@ static int nl80211_join_ibss(struct sk_
                break;
        case NL80211_CHAN_WIDTH_20:
        case NL80211_CHAN_WIDTH_40:
-               if (rdev->wiphy.features & NL80211_FEATURE_HT_IBSS)
-                       break;
+               if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
+                       return -EINVAL;
+               break;
+       case NL80211_CHAN_WIDTH_80:
+       case NL80211_CHAN_WIDTH_80P80:
+       case NL80211_CHAN_WIDTH_160:
+               if (!(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
+                       return -EINVAL;
+               if (!wiphy_ext_feature_isset(&rdev->wiphy,
+                                            NL80211_EXT_FEATURE_VHT_IBSS))
+                       return -EINVAL;
+               break;
        default:
                return -EINVAL;
        }
@@@ -7389,8 -7400,8 +7410,8 @@@ static int nl80211_set_mcast_rate(struc
  
  static struct sk_buff *
  __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
-                           int approxlen, u32 portid, u32 seq,
-                           enum nl80211_commands cmd,
+                           struct wireless_dev *wdev, int approxlen,
+                           u32 portid, u32 seq, enum nl80211_commands cmd,
                            enum nl80211_attrs attr,
                            const struct nl80211_vendor_cmd_info *info,
                            gfp_t gfp)
                        goto nla_put_failure;
        }
  
+       if (wdev) {
+               if (nla_put_u64(skb, NL80211_ATTR_WDEV,
+                               wdev_id(wdev)))
+                       goto nla_put_failure;
+               if (wdev->netdev &&
+                   nla_put_u32(skb, NL80211_ATTR_IFINDEX,
+                               wdev->netdev->ifindex))
+                       goto nla_put_failure;
+       }
        data = nla_nest_start(skb, attr);
  
        ((void **)skb->cb)[0] = rdev;
  }
  
  struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+                                          struct wireless_dev *wdev,
                                           enum nl80211_commands cmd,
                                           enum nl80211_attrs attr,
                                           int vendor_event_idx,
                return NULL;
        }
  
-       return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
+       return __cfg80211_alloc_vendor_skb(rdev, wdev, approxlen, 0, 0,
                                           cmd, attr, info, gfp);
  }
  EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
@@@ -8761,8 -8783,8 +8793,8 @@@ static int nl80211_send_wowlan_tcp(stru
        if (!nl_tcp)
                return -ENOBUFS;
  
 -      if (nla_put_be32(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) ||
 -          nla_put_be32(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) ||
 +      if (nla_put_in_addr(msg, NL80211_WOWLAN_TCP_SRC_IPV4, tcp->src) ||
 +          nla_put_in_addr(msg, NL80211_WOWLAN_TCP_DST_IPV4, tcp->dst) ||
            nla_put(msg, NL80211_WOWLAN_TCP_DST_MAC, ETH_ALEN, tcp->dst_mac) ||
            nla_put_u16(msg, NL80211_WOWLAN_TCP_SRC_PORT, tcp->src_port) ||
            nla_put_u16(msg, NL80211_WOWLAN_TCP_DST_PORT, tcp->dst_port) ||
@@@ -8808,6 -8830,9 +8840,9 @@@ static int nl80211_send_wowlan_nd(struc
        if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval))
                return -ENOBUFS;
  
+       if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_DELAY, req->delay))
+               return -ENOBUFS;
        freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
        if (!freqs)
                return -ENOBUFS;
@@@ -8993,8 -9018,8 +9028,8 @@@ static int nl80211_parse_wowlan_tcp(str
        cfg = kzalloc(size, GFP_KERNEL);
        if (!cfg)
                return -ENOMEM;
 -      cfg->src = nla_get_be32(tb[NL80211_WOWLAN_TCP_SRC_IPV4]);
 -      cfg->dst = nla_get_be32(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
 +      cfg->src = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_SRC_IPV4]);
 +      cfg->dst = nla_get_in_addr(tb[NL80211_WOWLAN_TCP_DST_IPV4]);
        memcpy(cfg->dst_mac, nla_data(tb[NL80211_WOWLAN_TCP_DST_MAC]),
               ETH_ALEN);
        if (tb[NL80211_WOWLAN_TCP_SRC_PORT])
@@@ -9094,6 -9119,7 +9129,7 @@@ static int nl80211_set_wowlan(struct sk
        const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
        int err, i;
        bool prev_enabled = rdev->wiphy.wowlan_config;
+       bool regular = false;
  
        if (!wowlan)
                return -EOPNOTSUPP;
                if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
                        return -EINVAL;
                new_triggers.disconnect = true;
+               regular = true;
        }
  
        if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
                if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
                        return -EINVAL;
                new_triggers.magic_pkt = true;
+               regular = true;
        }
  
        if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
                if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
                        return -EINVAL;
                new_triggers.gtk_rekey_failure = true;
+               regular = true;
        }
  
        if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
                if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
                        return -EINVAL;
                new_triggers.eap_identity_req = true;
+               regular = true;
        }
  
        if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
                if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
                        return -EINVAL;
                new_triggers.four_way_handshake = true;
+               regular = true;
        }
  
        if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
                if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
                        return -EINVAL;
                new_triggers.rfkill_release = true;
+               regular = true;
        }
  
        if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
                int rem, pat_len, mask_len, pkt_offset;
                struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
  
+               regular = true;
                nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
                                    rem)
                        n_patterns++;
        }
  
        if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
+               regular = true;
                err = nl80211_parse_wowlan_tcp(
                        rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
                        &new_triggers);
        }
  
        if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
+               regular = true;
                err = nl80211_parse_wowlan_nd(
                        rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
                        &new_triggers);
                        goto error;
        }
  
+       /* The 'any' trigger means the device continues operating more or less
+        * as in its normal operation mode and wakes up the host on most of the
+        * normal interrupts (like packet RX, ...)
+        * It therefore makes little sense to combine with the more constrained
+        * wakeup trigger modes.
+        */
+       if (new_triggers.any && regular) {
+               err = -EINVAL;
+               goto error;
+       }
        ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
        if (!ntrig) {
                err = -ENOMEM;
@@@ -9906,7 -9953,7 +9963,7 @@@ struct sk_buff *__cfg80211_alloc_reply_
        if (WARN_ON(!rdev->cur_cmd_info))
                return NULL;
  
-       return __cfg80211_alloc_vendor_skb(rdev, approxlen,
+       return __cfg80211_alloc_vendor_skb(rdev, NULL, approxlen,
                                           rdev->cur_cmd_info->snd_portid,
                                           rdev->cur_cmd_info->snd_seq,
                                           cmd, attr, NULL, GFP_KERNEL);
@@@ -12538,7 -12585,9 +12595,7 @@@ static int cfg80211_net_detect_results(
                        }
  
                        for (j = 0; j < match->n_channels; j++) {
 -                              if (nla_put_u32(msg,
 -                                              NL80211_ATTR_WIPHY_FREQ,
 -                                              match->channels[j])) {
 +                              if (nla_put_u32(msg, j, match->channels[j])) {
                                        nla_nest_cancel(msg, nl_freqs);
                                        nla_nest_cancel(msg, nl_match);
                                        goto out;
@@@ -12775,6 -12824,11 +12832,11 @@@ static int nl80211_netlink_notify(struc
  
        rcu_read_unlock();
  
+       /*
+        * It is possible that the user space process that is controlling the
+        * indoor setting disappeared, so notify the regulatory core.
+        */
+       regulatory_netlink_notify(notify->portid);
        return NOTIFY_OK;
  }
  
diff --combined net/wireless/reg.c
   *    be intersected with the current one.
   * @REG_REQ_ALREADY_SET: the regulatory request will not change the current
   *    regulatory settings, and no further processing is required.
-  * @REG_REQ_USER_HINT_HANDLED: a non alpha2  user hint was handled and no
-  *    further processing is required, i.e., not need to update last_request
-  *    etc. This should be used for user hints that do not provide an alpha2
-  *    but some other type of regulatory hint, i.e., indoor operation.
   */
  enum reg_request_treatment {
        REG_REQ_OK,
        REG_REQ_IGNORE,
        REG_REQ_INTERSECT,
        REG_REQ_ALREADY_SET,
-       REG_REQ_USER_HINT_HANDLED,
  };
  
  static struct regulatory_request core_request_world = {
@@@ -133,9 -128,12 +128,12 @@@ static int reg_num_devs_support_basehin
   * State variable indicating if the platform on which the devices
   * are attached is operating in an indoor environment. The state variable
   * is relevant for all registered devices.
-  * (protected by RTNL)
   */
  static bool reg_is_indoor;
+ static spinlock_t reg_indoor_lock;
+ /* Used to track the userspace process controlling the indoor setting */
+ static u32 reg_is_indoor_portid;
  
  static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
  {
@@@ -228,7 -226,7 +226,7 @@@ static DECLARE_DELAYED_WORK(reg_timeout
  
  /* We keep a static world regulatory domain in case of the absence of CRDA */
  static const struct ieee80211_regdomain world_regdom = {
 -      .n_reg_rules = 6,
 +      .n_reg_rules = 8,
        .alpha2 =  "00",
        .reg_rules = {
                /* IEEE 802.11b/g, channels 1..11 */
@@@ -554,6 -552,9 +552,9 @@@ reg_call_crda(struct regulatory_reques
  {
        if (call_crda(request->alpha2))
                return REG_REQ_IGNORE;
+       queue_delayed_work(system_power_efficient_wq,
+                          &reg_timeout, msecs_to_jiffies(3142));
        return REG_REQ_OK;
  }
  
@@@ -1248,13 -1249,6 +1249,6 @@@ static bool reg_request_cell_base(struc
        return request->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE;
  }
  
- static bool reg_request_indoor(struct regulatory_request *request)
- {
-       if (request->initiator != NL80211_REGDOM_SET_BY_USER)
-               return false;
-       return request->user_reg_hint_type == NL80211_USER_REG_HINT_INDOOR;
- }
  bool reg_last_request_cell_base(void)
  {
        return reg_request_cell_base(get_last_request());
@@@ -1800,8 -1794,7 +1794,7 @@@ static void reg_set_request_processed(v
                need_more_processing = true;
        spin_unlock(&reg_requests_lock);
  
-       if (lr->initiator == NL80211_REGDOM_SET_BY_USER)
-               cancel_delayed_work(&reg_timeout);
+       cancel_delayed_work(&reg_timeout);
  
        if (need_more_processing)
                schedule_work(&reg_work);
@@@ -1833,11 -1826,6 +1826,6 @@@ __reg_process_hint_user(struct regulato
  {
        struct regulatory_request *lr = get_last_request();
  
-       if (reg_request_indoor(user_request)) {
-               reg_is_indoor = true;
-               return REG_REQ_USER_HINT_HANDLED;
-       }
        if (reg_request_cell_base(user_request))
                return reg_ignore_cell_hint(user_request);
  
@@@ -1885,8 -1873,7 +1873,7 @@@ reg_process_hint_user(struct regulatory
  
        treatment = __reg_process_hint_user(user_request);
        if (treatment == REG_REQ_IGNORE ||
-           treatment == REG_REQ_ALREADY_SET ||
-           treatment == REG_REQ_USER_HINT_HANDLED) {
+           treatment == REG_REQ_ALREADY_SET) {
                reg_free_request(user_request);
                return treatment;
        }
@@@ -1947,7 -1934,6 +1934,6 @@@ reg_process_hint_driver(struct wiphy *w
        case REG_REQ_OK:
                break;
        case REG_REQ_IGNORE:
-       case REG_REQ_USER_HINT_HANDLED:
                reg_free_request(driver_request);
                return treatment;
        case REG_REQ_INTERSECT:
@@@ -2047,7 -2033,6 +2033,6 @@@ reg_process_hint_country_ie(struct wiph
        case REG_REQ_OK:
                break;
        case REG_REQ_IGNORE:
-       case REG_REQ_USER_HINT_HANDLED:
                /* fall through */
        case REG_REQ_ALREADY_SET:
                reg_free_request(country_ie_request);
@@@ -2086,11 -2071,8 +2071,8 @@@ static void reg_process_hint(struct reg
        case NL80211_REGDOM_SET_BY_USER:
                treatment = reg_process_hint_user(reg_request);
                if (treatment == REG_REQ_IGNORE ||
-                   treatment == REG_REQ_ALREADY_SET ||
-                   treatment == REG_REQ_USER_HINT_HANDLED)
+                   treatment == REG_REQ_ALREADY_SET)
                        return;
-               queue_delayed_work(system_power_efficient_wq,
-                                  &reg_timeout, msecs_to_jiffies(3142));
                return;
        case NL80211_REGDOM_SET_BY_DRIVER:
                if (!wiphy)
@@@ -2177,6 -2159,13 +2159,13 @@@ static void reg_process_pending_hints(v
        }
  
        reg_process_hint(reg_request);
+       lr = get_last_request();
+       spin_lock(&reg_requests_lock);
+       if (!list_empty(&reg_requests_list) && lr && lr->processed)
+               schedule_work(&reg_work);
+       spin_unlock(&reg_requests_lock);
  }
  
  /* Processes beacon hints -- this has nothing to do with country IEs */
@@@ -2309,22 -2298,50 +2298,50 @@@ int regulatory_hint_user(const char *al
        return 0;
  }
  
- int regulatory_hint_indoor_user(void)
+ int regulatory_hint_indoor(bool is_indoor, u32 portid)
  {
-       struct regulatory_request *request;
+       spin_lock(&reg_indoor_lock);
  
-       request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
-       if (!request)
-               return -ENOMEM;
+       /* It is possible that more than one user space process is trying to
+        * configure the indoor setting. To handle such cases, clear the indoor
+        * setting in case that some process does not think that the device
+        * is operating in an indoor environment. In addition, if a user space
+        * process indicates that it is controlling the indoor setting, save its
+        * portid, i.e., make it the owner.
+        */
+       reg_is_indoor = is_indoor;
+       if (reg_is_indoor) {
+               if (!reg_is_indoor_portid)
+                       reg_is_indoor_portid = portid;
+       } else {
+               reg_is_indoor_portid = 0;
+       }
  
-       request->wiphy_idx = WIPHY_IDX_INVALID;
-       request->initiator = NL80211_REGDOM_SET_BY_USER;
-       request->user_reg_hint_type = NL80211_USER_REG_HINT_INDOOR;
-       queue_regulatory_request(request);
+       spin_unlock(&reg_indoor_lock);
+       if (!is_indoor)
+               reg_check_channels();
  
        return 0;
  }
  
+ void regulatory_netlink_notify(u32 portid)
+ {
+       spin_lock(&reg_indoor_lock);
+       if (reg_is_indoor_portid != portid) {
+               spin_unlock(&reg_indoor_lock);
+               return;
+       }
+       reg_is_indoor = false;
+       reg_is_indoor_portid = 0;
+       spin_unlock(&reg_indoor_lock);
+       reg_check_channels();
+ }
  /* Driver hints */
  int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
  {
@@@ -2486,13 -2503,22 +2503,22 @@@ static void restore_regulatory_settings
        char alpha2[2];
        char world_alpha2[2];
        struct reg_beacon *reg_beacon, *btmp;
-       struct regulatory_request *reg_request, *tmp;
        LIST_HEAD(tmp_reg_req_list);
        struct cfg80211_registered_device *rdev;
  
        ASSERT_RTNL();
  
-       reg_is_indoor = false;
+       /*
+        * Clear the indoor setting in case that it is not controlled by user
+        * space, as otherwise there is no guarantee that the device is still
+        * operating in an indoor environment.
+        */
+       spin_lock(&reg_indoor_lock);
+       if (reg_is_indoor && !reg_is_indoor_portid) {
+               reg_is_indoor = false;
+               reg_check_channels();
+       }
+       spin_unlock(&reg_indoor_lock);
  
        reset_regdomains(true, &world_regdom);
        restore_alpha2(alpha2, reset_user);
         * settings.
         */
        spin_lock(&reg_requests_lock);
-       list_for_each_entry_safe(reg_request, tmp, &reg_requests_list, list) {
-               if (reg_request->initiator != NL80211_REGDOM_SET_BY_USER)
-                       continue;
-               list_move_tail(&reg_request->list, &tmp_reg_req_list);
-       }
+       list_splice_tail_init(&reg_requests_list, &tmp_reg_req_list);
        spin_unlock(&reg_requests_lock);
  
        /* Clear beacon hints */
@@@ -3089,6 -3111,7 +3111,7 @@@ int __init regulatory_init(void
  
        spin_lock_init(&reg_requests_lock);
        spin_lock_init(&reg_pending_beacons_lock);
+       spin_lock_init(&reg_indoor_lock);
  
        reg_regdb_size_check();
  
diff --combined net/wireless/trace.h
@@@ -7,7 -7,6 +7,7 @@@
  #include <linux/tracepoint.h>
  
  #include <linux/rtnetlink.h>
 +#include <linux/etherdevice.h>
  #include <net/cfg80211.h>
  #include "core.h"
  
@@@ -16,7 -15,7 +16,7 @@@
        if (given_mac)                                               \
                memcpy(__entry->entry_mac, given_mac, ETH_ALEN);     \
        else                                                         \
 -              memset(__entry->entry_mac, 0, ETH_ALEN);             \
 +              eth_zero_addr(__entry->entry_mac);                   \
        } while (0)
  #define MAC_PR_FMT "%pM"
  #define MAC_PR_ARG(entry_mac) (__entry->entry_mac)
@@@ -628,6 -627,7 +628,7 @@@ DECLARE_EVENT_CLASS(station_add_change
                __field(u8, plink_state)
                __field(u8, uapsd_queues)
                __array(u8, ht_capa, (int)sizeof(struct ieee80211_ht_cap))
+               __array(char, vlan, IFNAMSIZ)
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
                if (params->ht_capa)
                        memcpy(__entry->ht_capa, params->ht_capa,
                               sizeof(struct ieee80211_ht_cap));
+               memset(__entry->vlan, 0, sizeof(__entry->vlan));
+               if (params->vlan)
+                       memcpy(__entry->vlan, params->vlan->name, IFNAMSIZ);
        ),
        TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
                  ", station flags mask: %u, station flags set: %u, "
                  "station modify mask: %u, listen interval: %d, aid: %u, "
-                 "plink action: %u, plink state: %u, uapsd queues: %u",
+                 "plink action: %u, plink state: %u, uapsd queues: %u, vlan:%s",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac),
                  __entry->sta_flags_mask, __entry->sta_flags_set,
                  __entry->sta_modify_mask, __entry->listen_interval,
                  __entry->aid, __entry->plink_action, __entry->plink_state,
-                 __entry->uapsd_queues)
+                 __entry->uapsd_queues, __entry->vlan)
  );
  
  DEFINE_EVENT(station_add_change, rdev_add_station,
@@@ -1078,7 -1081,7 +1082,7 @@@ TRACE_EVENT(rdev_auth
                if (req->bss)
                        MAC_ASSIGN(bssid, req->bss->bssid);
                else
 -                      memset(__entry->bssid, 0, ETH_ALEN);
 +                      eth_zero_addr(__entry->bssid);
                __entry->auth_type = req->auth_type;
        ),
        TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", auth type: %d, bssid: " MAC_PR_FMT,
@@@ -1104,7 -1107,7 +1108,7 @@@ TRACE_EVENT(rdev_assoc
                if (req->bss)
                        MAC_ASSIGN(bssid, req->bss->bssid);
                else
 -                      memset(__entry->bssid, 0, ETH_ALEN);
 +                      eth_zero_addr(__entry->bssid);
                MAC_ASSIGN(prev_bssid, req->prev_bssid);
                __entry->use_mfp = req->use_mfp;
                __entry->flags = req->flags;
@@@ -1154,7 -1157,7 +1158,7 @@@ TRACE_EVENT(rdev_disassoc
                if (req->bss)
                        MAC_ASSIGN(bssid, req->bss->bssid);
                else
 -                      memset(__entry->bssid, 0, ETH_ALEN);
 +                      eth_zero_addr(__entry->bssid);
                __entry->reason_code = req->reason_code;
                __entry->local_state_change = req->local_state_change;
        ),
@@@ -2637,28 -2640,30 +2641,30 @@@ DEFINE_EVENT(wiphy_only_evt, cfg80211_s
  TRACE_EVENT(cfg80211_get_bss,
        TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
                 const u8 *bssid, const u8 *ssid, size_t ssid_len,
-                u16 capa_mask, u16 capa_val),
-       TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, capa_mask, capa_val),
+                enum ieee80211_bss_type bss_type,
+                enum ieee80211_privacy privacy),
+       TP_ARGS(wiphy, channel, bssid, ssid, ssid_len, bss_type, privacy),
        TP_STRUCT__entry(
                WIPHY_ENTRY
                CHAN_ENTRY
                MAC_ENTRY(bssid)
                __dynamic_array(u8, ssid, ssid_len)
-               __field(u16, capa_mask)
-               __field(u16, capa_val)
+               __field(enum ieee80211_bss_type, bss_type)
+               __field(enum ieee80211_privacy, privacy)
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
                CHAN_ASSIGN(channel);
                MAC_ASSIGN(bssid, bssid);
                memcpy(__get_dynamic_array(ssid), ssid, ssid_len);
-               __entry->capa_mask = capa_mask;
-               __entry->capa_val = capa_val;
-       ),
-       TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT ", buf: %#.2x, "
-                 "capa_mask: %d, capa_val: %u", WIPHY_PR_ARG, CHAN_PR_ARG,
-                 MAC_PR_ARG(bssid), ((u8 *)__get_dynamic_array(ssid))[0],
-                 __entry->capa_mask, __entry->capa_val)
+               __entry->bss_type = bss_type;
+               __entry->privacy = privacy;
+       ),
+       TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT
+                 ", buf: %#.2x, bss_type: %d, privacy: %d",
+                 WIPHY_PR_ARG, CHAN_PR_ARG, MAC_PR_ARG(bssid),
+                 ((u8 *)__get_dynamic_array(ssid))[0], __entry->bss_type,
+                 __entry->privacy)
  );
  
  TRACE_EVENT(cfg80211_inform_bss_width_frame,