*/
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)
{