*/
 void ieee80211_connection_loss(struct ieee80211_vif *vif);
 
+/**
+ * ieee80211_resume_disconnect - disconnect from AP after resume
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * Instructs mac80211 to disconnect from the AP after resume.
+ * Drivers can use this after WoWLAN if they know that the
+ * connection cannot be kept up, for example because keys were
+ * used while the device was asleep but the replay counters or
+ * similar cannot be retrieved from the device during resume.
+ *
+ * Note that due to implementation issues, if the driver uses
+ * the reconfiguration functionality during resume the interface
+ * will still be added as associated first during resume and then
+ * disconnect normally later.
+ *
+ * This function can only be called from the resume callback and
+ * the driver must not be holding any of its own locks while it
+ * calls this function, or at least not any locks it needs in the
+ * key configuration paths (if it supports HW crypto).
+ */
+void ieee80211_resume_disconnect(struct ieee80211_vif *vif);
+
 /**
  * ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm
  *
 
  * @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between
  *     associated stations and deliver multicast frames both
  *     back to wireless media and to the local net stack.
+ * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume.
  */
 enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_ALLMULTI                = BIT(0),
        IEEE80211_SDATA_PROMISC                 = BIT(1),
        IEEE80211_SDATA_OPERATING_GMODE         = BIT(2),
        IEEE80211_SDATA_DONT_BRIDGE_PACKETS     = BIT(3),
+       IEEE80211_SDATA_DISCONNECT_RESUME       = BIT(4),
 };
 
 /**
 
  *
  * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present
  *     in the hardware for TX crypto hardware acceleration.
+ * @KEY_FLAG_TAINTED: Key is tainted and packets should be dropped.
  */
 enum ieee80211_internal_key_flags {
        KEY_FLAG_UPLOADED_TO_HARDWARE   = BIT(0),
+       KEY_FLAG_TAINTED                = BIT(1),
 };
 
 enum ieee80211_internal_tkip_state {
 
 }
 
 static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
-                                         u8 *bssid)
+                                         u8 *bssid, u8 reason)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
         * but that's not a problem.
         */
        ieee80211_send_deauth_disassoc(sdata, bssid,
-                       IEEE80211_STYPE_DEAUTH,
-                       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
+                       IEEE80211_STYPE_DEAUTH, reason,
                        NULL, true);
        mutex_lock(&ifmgd->mtx);
 }
                                            " AP %pM, disconnecting.\n",
                                            sdata->name, bssid);
 #endif
-                               ieee80211_sta_connection_lost(sdata, bssid);
+                               ieee80211_sta_connection_lost(sdata, bssid,
+                                       WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
                        }
                } else if (time_is_after_jiffies(ifmgd->probe_timeout))
                        run_again(ifmgd, ifmgd->probe_timeout);
                                    sdata->name,
                                    bssid, probe_wait_ms);
 #endif
-                       ieee80211_sta_connection_lost(sdata, bssid);
+                       ieee80211_sta_connection_lost(sdata, bssid,
+                               WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
                } else if (ifmgd->probe_send_count < max_tries) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
                        wiphy_debug(local->hw.wiphy,
                                    sdata->name,
                                    bssid, probe_wait_ms);
 
-                       ieee80211_sta_connection_lost(sdata, bssid);
+                       ieee80211_sta_connection_lost(sdata, bssid,
+                               WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
                }
        }
 
        if (!ifmgd->associated)
                return;
 
+       if (sdata->flags & IEEE80211_SDATA_DISCONNECT_RESUME) {
+               sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME;
+               mutex_lock(&ifmgd->mtx);
+               if (ifmgd->associated) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+                       wiphy_debug(sdata->local->hw.wiphy,
+                                   "%s: driver requested disconnect after resume.\n",
+                                   sdata->name);
+#endif
+                       ieee80211_sta_connection_lost(sdata,
+                               ifmgd->associated->bssid,
+                               WLAN_REASON_UNSPECIFIED);
+                       mutex_unlock(&ifmgd->mtx);
+                       return;
+               }
+               mutex_unlock(&ifmgd->mtx);
+       }
+
        if (test_and_clear_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running))
                add_timer(&ifmgd->timer);
        if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))
 
        }
 
        if (rx->key) {
+               if (unlikely(rx->key->flags & KEY_FLAG_TAINTED))
+                       return RX_DROP_MONITOR;
+
                rx->key->tx_rx_count++;
                /* TODO: add threshold stuff again */
        } else {
 
                        break;
                }
 
+               if (unlikely(tx->key && tx->key->flags & KEY_FLAG_TAINTED))
+                       return TX_DROP;
+
                if (!skip_hw && tx->key &&
                    tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)
                        info->control.hw_key = &tx->key->conf;
 
        return 0;
 }
 
+void ieee80211_resume_disconnect(struct ieee80211_vif *vif)
+{
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_local *local;
+       struct ieee80211_key *key;
+
+       if (WARN_ON(!vif))
+               return;
+
+       sdata = vif_to_sdata(vif);
+       local = sdata->local;
+
+       if (WARN_ON(!local->resuming))
+               return;
+
+       if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
+               return;
+
+       sdata->flags |= IEEE80211_SDATA_DISCONNECT_RESUME;
+
+       mutex_lock(&local->key_mtx);
+       list_for_each_entry(key, &sdata->key_list, list)
+               key->flags |= KEY_FLAG_TAINTED;
+       mutex_unlock(&local->key_mtx);
+}
+EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
+
 static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
                          enum ieee80211_smps_mode *smps_mode)
 {