+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -31,10 +31,12 @@
+ #include "led.h"
+
+ #define IEEE80211_AUTH_TIMEOUT (HZ / 5)
++#define IEEE80211_AUTH_TIMEOUT_LONG (HZ / 2)
+ #define IEEE80211_AUTH_TIMEOUT_SHORT (HZ / 10)
+ #define IEEE80211_AUTH_MAX_TRIES 3
+ #define IEEE80211_AUTH_WAIT_ASSOC (HZ * 5)
+ #define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
++#define IEEE80211_ASSOC_TIMEOUT_LONG (HZ / 2)
+ #define IEEE80211_ASSOC_TIMEOUT_SHORT (HZ / 10)
+ #define IEEE80211_ASSOC_MAX_TRIES 3
+
+@@ -209,8 +211,9 @@ ieee80211_determine_chantype(struct ieee
+ struct ieee80211_channel *channel,
+ const struct ieee80211_ht_operation *ht_oper,
+ const struct ieee80211_vht_operation *vht_oper,
+- struct cfg80211_chan_def *chandef, bool verbose)
++ struct cfg80211_chan_def *chandef, bool tracking)
+ {
++ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ struct cfg80211_chan_def vht_chandef;
+ u32 ht_cfreq, ret;
+
+@@ -229,7 +232,7 @@ ieee80211_determine_chantype(struct ieee
+ ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
+ channel->band);
+ /* check that channel matches the right operating channel */
+- if (channel->center_freq != ht_cfreq) {
++ if (!tracking && channel->center_freq != ht_cfreq) {
+ /*
+ * It's possible that some APs are confused here;
+ * Netgear WNDR3700 sometimes reports 4 higher than
+@@ -237,11 +240,10 @@ ieee80211_determine_chantype(struct ieee
+ * since we look at probe response/beacon data here
+ * it should be OK.
+ */
+- if (verbose)
+- sdata_info(sdata,
+- "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
+- channel->center_freq, ht_cfreq,
+- ht_oper->primary_chan, channel->band);
++ sdata_info(sdata,
++ "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
++ channel->center_freq, ht_cfreq,
++ ht_oper->primary_chan, channel->band);
+ ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+ goto out;
+ }
+@@ -295,7 +297,7 @@ ieee80211_determine_chantype(struct ieee
+ channel->band);
+ break;
+ default:
+- if (verbose)
++ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
+ sdata_info(sdata,
+ "AP VHT operation IE has invalid channel width (%d), disable VHT\n",
+ vht_oper->chan_width);
+@@ -304,7 +306,7 @@ ieee80211_determine_chantype(struct ieee
+ }
+
+ if (!cfg80211_chandef_valid(&vht_chandef)) {
+- if (verbose)
++ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
+ sdata_info(sdata,
+ "AP VHT information is invalid, disable VHT\n");
+ ret = IEEE80211_STA_DISABLE_VHT;
+@@ -317,7 +319,7 @@ ieee80211_determine_chantype(struct ieee
+ }
+
+ if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) {
+- if (verbose)
++ if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
+ sdata_info(sdata,
+ "AP VHT information doesn't match HT, disable VHT\n");
+ ret = IEEE80211_STA_DISABLE_VHT;
+@@ -333,18 +335,27 @@ out:
+ if (ret & IEEE80211_STA_DISABLE_VHT)
+ vht_chandef = *chandef;
+
++ /*
++ * Ignore the DISABLED flag when we're already connected and only
++ * tracking the APs beacon for bandwidth changes - otherwise we
++ * might get disconnected here if we connect to an AP, update our
++ * regulatory information based on the AP's country IE and the
++ * information we have is wrong/outdated and disables the channel
++ * that we're actually using for the connection to the AP.
++ */
+ while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
+- IEEE80211_CHAN_DISABLED)) {
++ tracking ? 0 :
++ IEEE80211_CHAN_DISABLED)) {
+ if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) {
+ ret = IEEE80211_STA_DISABLE_HT |
+ IEEE80211_STA_DISABLE_VHT;
+- goto out;
++ break;
+ }
+
+ ret |= chandef_downgrade(chandef);
+ }
+
+- if (chandef->width != vht_chandef.width && verbose)
++ if (chandef->width != vht_chandef.width && !tracking)
+ sdata_info(sdata,
+ "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n");
+
+@@ -384,7 +395,7 @@ static int ieee80211_config_bw(struct ie
+
+ /* calculate new channel (type) based on HT/VHT operation IEs */
+ flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper,
+- vht_oper, &chandef, false);
++ vht_oper, &chandef, true);
+
+ /*
+ * Downgrade the new channel if we associated with restricted
+@@ -3394,10 +3405,13 @@ static int ieee80211_probe_auth(struct i
+
+ if (tx_flags == 0) {
+ auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
+- ifmgd->auth_data->timeout_started = true;
++ auth_data->timeout_started = true;
+ run_again(sdata, auth_data->timeout);
+ } else {
+- auth_data->timeout_started = false;
++ auth_data->timeout =
++ round_jiffies_up(jiffies + IEEE80211_AUTH_TIMEOUT_LONG);
++ auth_data->timeout_started = true;
++ run_again(sdata, auth_data->timeout);
+ }
+
+ return 0;
+@@ -3434,7 +3448,11 @@ static int ieee80211_do_assoc(struct iee
+ assoc_data->timeout_started = true;
+ run_again(sdata, assoc_data->timeout);
+ } else {
+- assoc_data->timeout_started = false;
++ assoc_data->timeout =
++ round_jiffies_up(jiffies +
++ IEEE80211_ASSOC_TIMEOUT_LONG);
++ assoc_data->timeout_started = true;
++ run_again(sdata, assoc_data->timeout);
+ }
+
+ return 0;
+@@ -3829,7 +3847,7 @@ static int ieee80211_prep_channel(struct
+ ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
+ cbss->channel,
+ ht_oper, vht_oper,
+- &chandef, true);
++ &chandef, false);
+
+ sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
+ local->rx_chains);
+--- a/net/wireless/core.c
++++ b/net/wireless/core.c
+@@ -772,6 +772,7 @@ void cfg80211_leave(struct cfg80211_regi
+ cfg80211_leave_mesh(rdev, dev);
+ break;
+ case NL80211_IFTYPE_AP:
++ case NL80211_IFTYPE_P2P_GO:
+ cfg80211_stop_ap(rdev, dev);
+ break;
+ default: