IEEE80211_HW_REPORTS_TX_ACK_STATUS |
                     IEEE80211_HW_SUPPORTS_PS |
                     IEEE80211_HW_PS_NULLFUNC_STACK |
-                    IEEE80211_HW_NEED_DTIM_PERIOD |
+                    IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
                     IEEE80211_HW_SIGNAL_DBM;
 
        if (!modparam_noht) {
 
        /* Tell mac80211 our characteristics */
        hw->flags =
            IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_AMPDU_AGGREGATION |
-           IEEE80211_HW_NEED_DTIM_PERIOD | IEEE80211_HW_SPECTRUM_MGMT |
+           IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC | IEEE80211_HW_SPECTRUM_MGMT |
            IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SUPPORTS_PS |
            IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
        if (il->cfg->sku & IL_SKU_N)
 
        /* Tell mac80211 our characteristics */
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_AMPDU_AGGREGATION |
-                   IEEE80211_HW_NEED_DTIM_PERIOD |
+                   IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC |
                    IEEE80211_HW_SPECTRUM_MGMT |
                    IEEE80211_HW_REPORTS_TX_ACK_STATUS |
                    IEEE80211_HW_QUEUE_CONTROL |
 
  * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface
  * @BSS_CHANGED_P2P_PS: P2P powersave settings (CTWindow, opportunistic PS)
  *     changed (currently only in P2P client mode, GO mode will be later)
+ * @BSS_CHANGED_DTIM_PERIOD: the DTIM period value was changed (set when
+ *     it becomes valid, managed mode only)
  */
 enum ieee80211_bss_change {
        BSS_CHANGED_ASSOC               = 1<<0,
        BSS_CHANGED_PS                  = 1<<17,
        BSS_CHANGED_TXPOWER             = 1<<18,
        BSS_CHANGED_P2P_PS              = 1<<19,
+       BSS_CHANGED_DTIM_PERIOD         = 1<<20,
 
        /* when adding here, make sure to change ieee80211_reconfig */
 };
  *     if the hardware cannot handle this it must set the
  *     IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag
  * @dtim_period: num of beacons before the next DTIM, for beaconing,
- *     valid in station mode only while @assoc is true and if also
- *     requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf
- *     @ps_dtim_period)
+ *     valid in station mode only if after the driver was notified
+ *     with the %BSS_CHANGED_DTIM_PERIOD flag, will be non-zero then.
  * @sync_tsf: last beacon's/probe response's TSF timestamp (could be old
  *     as it may have been received during scanning long ago)
  * @sync_device_ts: the device timestamp corresponding to the sync_tsf,
  *      When this flag is set, signaling beacon-loss will cause an immediate
  *      change to disassociated state.
  *
- * @IEEE80211_HW_NEED_DTIM_PERIOD:
- *     This device needs to know the DTIM period for the BSS before
- *     associating.
+ * @IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC:
+ *     This device needs to get data from beacon before association (i.e.
+ *     dtim_period).
  *
  * @IEEE80211_HW_SUPPORTS_PER_STA_GTK: The device's crypto engine supports
  *     per-station GTKs as used by IBSS RSN or during fast transition. If
        IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE      = 1<<4,
        IEEE80211_HW_SIGNAL_UNSPEC                      = 1<<5,
        IEEE80211_HW_SIGNAL_DBM                         = 1<<6,
-       IEEE80211_HW_NEED_DTIM_PERIOD                   = 1<<7,
+       IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC             = 1<<7,
        IEEE80211_HW_SPECTRUM_MGMT                      = 1<<8,
        IEEE80211_HW_AMPDU_AGGREGATION                  = 1<<9,
        IEEE80211_HW_SUPPORTS_PS                        = 1<<10,
 
                sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n");
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n");
-       if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD)
-               sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_PERIOD\n");
+       if (local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC)
+               sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_BEFORE_ASSOC\n");
        if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)
                sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n");
        if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)
 
        u8 ssid_len;
        u8 supp_rates_len;
        bool wmm, uapsd;
-       bool have_beacon;
+       bool have_beacon, need_beacon;
        bool synced;
 
        u8 ap_ht_param;
 
 
        ieee80211_led_assoc(local, 1);
 
-       if (local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) {
+       if (sdata->u.mgd.assoc_data->have_beacon) {
                /*
                 * If the AP is buggy we may get here with no DTIM period
                 * known, so assume it's 1 which is the only safe assumption
                 * probably just won't work at all.
                 */
                bss_conf->dtim_period = sdata->u.mgd.dtim_period ?: 1;
+               bss_info_changed |= BSS_CHANGED_DTIM_PERIOD;
        } else {
                bss_conf->dtim_period = 0;
        }
        chan = chanctx_conf->def.chan;
        rcu_read_unlock();
 
-       if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon &&
+       if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
            ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
                ieee802_11_parse_elems(mgmt->u.beacon.variable,
                                       len - baselen, &elems);
 
                ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
                ifmgd->assoc_data->have_beacon = true;
+               ifmgd->assoc_data->need_beacon = false;
                /* continue assoc process */
                ifmgd->assoc_data->timeout = jiffies;
                run_again(ifmgd, ifmgd->assoc_data->timeout);
                                     elems.wmm_param_len))
                changed |= BSS_CHANGED_QOS;
 
+       /*
+        * If we haven't had a beacon before, tell the driver about the
+        * DTIM period now.
+        */
+       if (!bss_conf->dtim_period) {
+               /* a few bogus AP send dtim_period = 0 or no TIM IE */
+               if (elems.tim)
+                       bss_conf->dtim_period = elems.tim->dtim_period ?: 1;
+               else
+                       bss_conf->dtim_period = 1;
+               changed |= BSS_CHANGED_DTIM_PERIOD;
+       }
+
        if (elems.erp_info && elems.erp_info_len >= 1) {
                erp_valid = true;
                erp_value = elems.erp_info[0];
 
        if (ifmgd->assoc_data &&
            time_after(jiffies, ifmgd->assoc_data->timeout)) {
-               if (!ifmgd->assoc_data->have_beacon ||
+               if ((ifmgd->assoc_data->need_beacon &&
+                    !ifmgd->assoc_data->have_beacon) ||
                    ieee80211_do_assoc(sdata)) {
                        u8 bssid[ETH_ALEN];
 
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_bss *bss = (void *)req->bss->priv;
        struct ieee80211_mgd_assoc_data *assoc_data;
+       const struct cfg80211_bss_ies *beacon_ies;
        struct ieee80211_supported_band *sband;
        const u8 *ssidie, *ht_ie, *vht_ie;
        int i, err;
        if (err)
                goto err_clear;
 
-       if (sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_PERIOD) {
-               const struct cfg80211_bss_ies *beacon_ies;
+       rcu_read_lock();
+       beacon_ies = rcu_dereference(req->bss->beacon_ies);
 
-               rcu_read_lock();
-               beacon_ies = rcu_dereference(req->bss->beacon_ies);
-               if (!beacon_ies) {
-                       /*
-                        * Wait up to one beacon interval ...
-                        * should this be more if we miss one?
-                        */
-                       sdata_info(sdata, "waiting for beacon from %pM\n",
-                                  ifmgd->bssid);
-                       assoc_data->timeout =
-                               TU_TO_EXP_TIME(req->bss->beacon_interval);
-               } else {
-                       const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM,
-                                                           beacon_ies->data,
-                                                           beacon_ies->len);
-                       if (tim_ie && tim_ie[1] >=
-                                       sizeof(struct ieee80211_tim_ie)) {
-                               const struct ieee80211_tim_ie *tim;
-                               tim = (void *)(tim_ie + 2);
-                               ifmgd->dtim_period = tim->dtim_period;
-                       }
-                       assoc_data->have_beacon = true;
-                       assoc_data->timeout = jiffies;
+       if (sdata->local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC &&
+           !beacon_ies) {
+               /*
+                * Wait up to one beacon interval ...
+                * should this be more if we miss one?
+                */
+               sdata_info(sdata, "waiting for beacon from %pM\n",
+                          ifmgd->bssid);
+               assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval);
+               assoc_data->need_beacon = true;
+       } else if (beacon_ies) {
+               const u8 *tim_ie = cfg80211_find_ie(WLAN_EID_TIM,
+                                                   beacon_ies->data,
+                                                   beacon_ies->len);
+               if (tim_ie && tim_ie[1] >= sizeof(struct ieee80211_tim_ie)) {
+                       const struct ieee80211_tim_ie *tim;
+                       tim = (void *)(tim_ie + 2);
+                       ifmgd->dtim_period = tim->dtim_period;
                }
-               rcu_read_unlock();
-       } else {
                assoc_data->have_beacon = true;
                assoc_data->timeout = jiffies;
+       } else {
+               assoc_data->timeout = jiffies;
        }
+       rcu_read_unlock();
+
        run_again(ifmgd, assoc_data->timeout);
 
        if (bss->corrupt_data) {
 
                        changed |= BSS_CHANGED_ASSOC |
                                   BSS_CHANGED_ARP_FILTER |
                                   BSS_CHANGED_PS;
+
+                       if (sdata->u.mgd.dtim_period)
+                               changed |= BSS_CHANGED_DTIM_PERIOD;
+
                        mutex_lock(&sdata->u.mgd.mtx);
                        ieee80211_bss_info_change_notify(sdata, changed);
                        mutex_unlock(&sdata->u.mgd.mtx);