|
@@ -6,6 +6,7 @@
|
|
|
* GPL LICENSE SUMMARY
|
|
|
*
|
|
|
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
|
|
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
* it under the terms of version 2 of the GNU General Public License as
|
|
@@ -31,6 +32,7 @@
|
|
|
* BSD LICENSE
|
|
|
*
|
|
|
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
|
|
|
+ * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
|
|
|
* All rights reserved.
|
|
|
*
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
@@ -776,6 +778,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
|
|
|
iwl_trans_stop_device(mvm->trans);
|
|
|
|
|
|
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
|
|
+ mvm->ps_disabled = false;
|
|
|
|
|
|
/* just in case one was running */
|
|
|
ieee80211_remain_on_channel_expired(mvm->hw);
|
|
@@ -803,6 +806,9 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
|
|
|
* ucode_down ref until reconfig is complete */
|
|
|
iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
|
|
|
|
|
|
+ /* clear any stale d0i3 state */
|
|
|
+ clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
|
|
|
+
|
|
|
mvm->vif_count = 0;
|
|
|
mvm->rx_ba_sessions = 0;
|
|
|
}
|
|
@@ -880,7 +886,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
|
|
|
/* async_handlers_list is empty and will stay empty: HW is stopped */
|
|
|
|
|
|
/* the fw is stopped, the aux sta is dead: clean up driver state */
|
|
|
- iwl_mvm_dealloc_int_sta(mvm, &mvm->aux_sta);
|
|
|
+ iwl_mvm_del_aux_sta(mvm);
|
|
|
|
|
|
mutex_unlock(&mvm->mutex);
|
|
|
|
|
@@ -965,10 +971,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
|
|
|
*/
|
|
|
if (vif->type == NL80211_IFTYPE_AP ||
|
|
|
vif->type == NL80211_IFTYPE_ADHOC) {
|
|
|
- u32 qmask = iwl_mvm_mac_get_queues_mask(mvm, vif);
|
|
|
- ret = iwl_mvm_allocate_int_sta(mvm, &mvmvif->bcast_sta,
|
|
|
- qmask,
|
|
|
- ieee80211_vif_type_p2p(vif));
|
|
|
+ ret = iwl_mvm_alloc_bcast_sta(mvm, vif);
|
|
|
if (ret) {
|
|
|
IWL_ERR(mvm, "Failed to allocate bcast sta\n");
|
|
|
goto out_release;
|
|
@@ -1016,7 +1019,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
|
|
|
if (ret)
|
|
|
goto out_unref_phy;
|
|
|
|
|
|
- ret = iwl_mvm_add_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
|
|
|
+ ret = iwl_mvm_add_bcast_sta(mvm, vif);
|
|
|
if (ret)
|
|
|
goto out_unbind;
|
|
|
|
|
@@ -1057,14 +1060,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
|
|
|
static void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm,
|
|
|
struct ieee80211_vif *vif)
|
|
|
{
|
|
|
- u32 tfd_msk = 0, ac;
|
|
|
-
|
|
|
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
|
|
- if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
|
|
|
- tfd_msk |= BIT(vif->hw_queue[ac]);
|
|
|
-
|
|
|
- if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
|
|
|
- tfd_msk |= BIT(vif->cab_queue);
|
|
|
+ u32 tfd_msk = iwl_mvm_mac_get_queues_mask(mvm, vif);
|
|
|
|
|
|
if (tfd_msk) {
|
|
|
mutex_lock(&mvm->mutex);
|
|
@@ -1120,13 +1116,13 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
|
|
|
mvm->noa_duration = 0;
|
|
|
}
|
|
|
#endif
|
|
|
- iwl_mvm_dealloc_int_sta(mvm, &mvmvif->bcast_sta);
|
|
|
+ iwl_mvm_dealloc_bcast_sta(mvm, vif);
|
|
|
goto out_release;
|
|
|
}
|
|
|
|
|
|
if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
|
|
|
mvm->p2p_device_vif = NULL;
|
|
|
- iwl_mvm_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
|
|
|
+ iwl_mvm_rm_bcast_sta(mvm, vif);
|
|
|
iwl_mvm_binding_remove_vif(mvm, vif);
|
|
|
iwl_mvm_phy_ctxt_unref(mvm, mvmvif->phy_ctxt);
|
|
|
mvmvif->phy_ctxt = NULL;
|
|
@@ -1445,10 +1441,23 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
|
|
if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc)
|
|
|
iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
|
|
|
|
|
|
- ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false);
|
|
|
+ /*
|
|
|
+ * If we're not associated yet, take the (new) BSSID before associating
|
|
|
+ * so the firmware knows. If we're already associated, then use the old
|
|
|
+ * BSSID here, and we'll send a cleared one later in the CHANGED_ASSOC
|
|
|
+ * branch for disassociation below.
|
|
|
+ */
|
|
|
+ if (changes & BSS_CHANGED_BSSID && !mvmvif->associated)
|
|
|
+ memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN);
|
|
|
+
|
|
|
+ ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, mvmvif->bssid);
|
|
|
if (ret)
|
|
|
IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
|
|
|
|
|
|
+ /* after sending it once, adopt mac80211 data */
|
|
|
+ memcpy(mvmvif->bssid, bss_conf->bssid, ETH_ALEN);
|
|
|
+ mvmvif->associated = bss_conf->assoc;
|
|
|
+
|
|
|
if (changes & BSS_CHANGED_ASSOC) {
|
|
|
if (bss_conf->assoc) {
|
|
|
/* add quota for this interface */
|
|
@@ -1476,13 +1485,17 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
|
|
*/
|
|
|
u32 dur = (11 * vif->bss_conf.beacon_int) / 10;
|
|
|
iwl_mvm_protect_session(mvm, vif, dur, dur,
|
|
|
- 5 * dur);
|
|
|
+ 5 * dur, false);
|
|
|
}
|
|
|
|
|
|
iwl_mvm_sf_update(mvm, vif, false);
|
|
|
iwl_mvm_power_vif_assoc(mvm, vif);
|
|
|
- if (vif->p2p)
|
|
|
+ if (vif->p2p) {
|
|
|
iwl_mvm_ref(mvm, IWL_MVM_REF_P2P_CLIENT);
|
|
|
+ iwl_mvm_update_smps(mvm, vif,
|
|
|
+ IWL_MVM_SMPS_REQ_PROT,
|
|
|
+ IEEE80211_SMPS_DYNAMIC);
|
|
|
+ }
|
|
|
} else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
|
|
|
/*
|
|
|
* If update fails - SF might be running in associated
|
|
@@ -1506,6 +1519,13 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
|
|
|
|
|
if (vif->p2p)
|
|
|
iwl_mvm_unref(mvm, IWL_MVM_REF_P2P_CLIENT);
|
|
|
+
|
|
|
+ /* this will take the cleared BSSID from bss_conf */
|
|
|
+ ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
|
|
|
+ if (ret)
|
|
|
+ IWL_ERR(mvm,
|
|
|
+ "failed to update MAC %pM (clear after unassoc)\n",
|
|
|
+ vif->addr);
|
|
|
}
|
|
|
|
|
|
iwl_mvm_recalc_multicast(mvm);
|
|
@@ -1601,7 +1621,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
|
|
|
|
|
/* Send the bcast station. At this stage the TBTT and DTIM time events
|
|
|
* are added and applied to the scheduler */
|
|
|
- ret = iwl_mvm_send_bcast_sta(mvm, vif, &mvmvif->bcast_sta);
|
|
|
+ ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
|
|
|
if (ret)
|
|
|
goto out_unbind;
|
|
|
|
|
@@ -1617,7 +1637,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
|
|
|
|
|
/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
|
|
|
if (vif->p2p && mvm->p2p_device_vif)
|
|
|
- iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);
|
|
|
+ iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);
|
|
|
|
|
|
iwl_mvm_ref(mvm, IWL_MVM_REF_AP_IBSS);
|
|
|
|
|
@@ -1633,7 +1653,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
|
|
|
out_quota_failed:
|
|
|
iwl_mvm_power_update_mac(mvm);
|
|
|
mvmvif->ap_ibss_active = false;
|
|
|
- iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
|
|
|
+ iwl_mvm_send_rm_bcast_sta(mvm, vif);
|
|
|
out_unbind:
|
|
|
iwl_mvm_binding_remove_vif(mvm, vif);
|
|
|
out_remove:
|
|
@@ -1675,10 +1695,10 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw,
|
|
|
|
|
|
/* Need to update the P2P Device MAC (only GO, IBSS is single vif) */
|
|
|
if (vif->p2p && mvm->p2p_device_vif)
|
|
|
- iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false);
|
|
|
+ iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL);
|
|
|
|
|
|
iwl_mvm_update_quotas(mvm, NULL);
|
|
|
- iwl_mvm_send_rm_bcast_sta(mvm, &mvmvif->bcast_sta);
|
|
|
+ iwl_mvm_send_rm_bcast_sta(mvm, vif);
|
|
|
iwl_mvm_binding_remove_vif(mvm, vif);
|
|
|
|
|
|
iwl_mvm_power_update_mac(mvm);
|
|
@@ -1702,7 +1722,7 @@ iwl_mvm_bss_info_changed_ap_ibss(struct iwl_mvm *mvm,
|
|
|
|
|
|
if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT |
|
|
|
BSS_CHANGED_BANDWIDTH) &&
|
|
|
- iwl_mvm_mac_ctxt_changed(mvm, vif, false))
|
|
|
+ iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL))
|
|
|
IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
|
|
|
|
|
|
/* Need to send a new beacon template to the FW */
|
|
@@ -2113,7 +2133,7 @@ static int iwl_mvm_mac_conf_tx(struct ieee80211_hw *hw,
|
|
|
int ret;
|
|
|
|
|
|
mutex_lock(&mvm->mutex);
|
|
|
- ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false);
|
|
|
+ ret = iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
|
|
|
mutex_unlock(&mvm->mutex);
|
|
|
return ret;
|
|
|
}
|
|
@@ -2141,7 +2161,7 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
|
|
|
|
|
|
mutex_lock(&mvm->mutex);
|
|
|
/* Try really hard to protect the session and hear a beacon */
|
|
|
- iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500);
|
|
|
+ iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500, false);
|
|
|
mutex_unlock(&mvm->mutex);
|
|
|
|
|
|
iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX);
|
|
@@ -2162,7 +2182,7 @@ static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
|
|
|
|
|
|
mutex_lock(&mvm->mutex);
|
|
|
/* Protect the session to hear the TDLS setup response on the channel */
|
|
|
- iwl_mvm_protect_session(mvm, vif, duration, duration, 100);
|
|
|
+ iwl_mvm_protect_session(mvm, vif, duration, duration, 100, true);
|
|
|
mutex_unlock(&mvm->mutex);
|
|
|
|
|
|
iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS);
|
|
@@ -2700,7 +2720,10 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
|
|
|
ret = 0;
|
|
|
goto out;
|
|
|
case NL80211_IFTYPE_STATION:
|
|
|
+ break;
|
|
|
case NL80211_IFTYPE_MONITOR:
|
|
|
+ /* always disable PS when a monitor interface is active */
|
|
|
+ mvmvif->ps_disabled = true;
|
|
|
break;
|
|
|
default:
|
|
|
ret = -EINVAL;
|
|
@@ -2732,7 +2755,20 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
|
|
|
if ((vif->type == NL80211_IFTYPE_AP) ||
|
|
|
(switching_chanctx && (vif->type == NL80211_IFTYPE_STATION))) {
|
|
|
iwl_mvm_update_quotas(mvm, NULL);
|
|
|
- iwl_mvm_mac_ctxt_changed(mvm, vif, false);
|
|
|
+ iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (vif->csa_active && vif->type == NL80211_IFTYPE_STATION) {
|
|
|
+ struct iwl_mvm_sta *mvmsta;
|
|
|
+
|
|
|
+ mvmsta = iwl_mvm_sta_from_staid_protected(mvm,
|
|
|
+ mvmvif->ap_sta_id);
|
|
|
+
|
|
|
+ if (WARN_ON(!mvmsta))
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /* TODO: only re-enable after the first beacon */
|
|
|
+ iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false);
|
|
|
}
|
|
|
|
|
|
goto out;
|
|
@@ -2766,6 +2802,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
|
|
|
{
|
|
|
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
|
|
struct ieee80211_vif *disabled_vif = NULL;
|
|
|
+ struct iwl_mvm_sta *mvmsta;
|
|
|
|
|
|
lockdep_assert_held(&mvm->mutex);
|
|
|
|
|
@@ -2776,6 +2813,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
|
|
|
goto out;
|
|
|
case NL80211_IFTYPE_MONITOR:
|
|
|
mvmvif->monitor_active = false;
|
|
|
+ mvmvif->ps_disabled = false;
|
|
|
break;
|
|
|
case NL80211_IFTYPE_AP:
|
|
|
/* This part is triggered only during CSA */
|
|
@@ -2796,7 +2834,13 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm,
|
|
|
|
|
|
disabled_vif = vif;
|
|
|
|
|
|
- iwl_mvm_mac_ctxt_changed(mvm, vif, true);
|
|
|
+ mvmsta = iwl_mvm_sta_from_staid_protected(mvm,
|
|
|
+ mvmvif->ap_sta_id);
|
|
|
+
|
|
|
+ if (!WARN_ON(!mvmsta))
|
|
|
+ iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true);
|
|
|
+
|
|
|
+ iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);
|
|
|
break;
|
|
|
default:
|
|
|
break;
|