static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mac_ctx_cmd *cmd,
+ const u8 *bssid_override,
u32 action)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
bool ht_enabled = !!(vif->bss_conf.ht_operation_mode &
IEEE80211_HT_OP_MODE_PROTECTION);
u8 cck_ack_rates, ofdm_ack_rates;
+ const u8 *bssid = bssid_override ?: vif->bss_conf.bssid;
int i;
cmd->id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
cmd->tsf_id = cpu_to_le32(mvmvif->tsf_id);
memcpy(cmd->node_addr, vif->addr, ETH_ALEN);
- if (vif->bss_conf.bssid)
- memcpy(cmd->bssid_addr, vif->bss_conf.bssid, ETH_ALEN);
+
+ if (bssid)
+ memcpy(cmd->bssid_addr, bssid, ETH_ALEN);
else
eth_broadcast_addr(cmd->bssid_addr);
static int iwl_mvm_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- u32 action, bool force_assoc_off)
+ u32 action, bool force_assoc_off,
+ const u8 *bssid_override)
{
struct iwl_mac_ctx_cmd cmd = {};
struct iwl_mac_data_sta *ctxt_sta;
WARN_ON(vif->type != NL80211_IFTYPE_STATION);
/* Fill the common data for all mac context types */
- iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, bssid_override, action);
if (vif->p2p) {
struct ieee80211_p2p_noa_attr *noa =
WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
- iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_PROMISC |
MAC_FILTER_IN_CONTROL_AND_MGMT |
WARN_ON(vif->type != NL80211_IFTYPE_ADHOC);
- iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
cmd.filter_flags = cpu_to_le32(MAC_FILTER_IN_BEACON |
MAC_FILTER_IN_PROBE_REQUEST);
WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);
- iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
cmd.protection_flags |= cpu_to_le32(MAC_PROT_FLG_TGG_PROTECT);
WARN_ON(vif->type != NL80211_IFTYPE_AP || vif->p2p);
/* Fill the common data for all mac context types */
- iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/*
* pass probe requests and beacons from other APs (needed
WARN_ON(vif->type != NL80211_IFTYPE_AP || !vif->p2p);
/* Fill the common data for all mac context types */
- iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
+ iwl_mvm_mac_ctxt_cmd_common(mvm, vif, &cmd, NULL, action);
/*
* pass probe requests and beacons from other APs (needed
}
static int iwl_mvm_mac_ctx_send(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- u32 action, bool force_assoc_off)
+ u32 action, bool force_assoc_off,
+ const u8 *bssid_override)
{
switch (vif->type) {
case NL80211_IFTYPE_STATION:
return iwl_mvm_mac_ctxt_cmd_sta(mvm, vif, action,
- force_assoc_off);
+ force_assoc_off,
+ bssid_override);
break;
case NL80211_IFTYPE_AP:
if (!vif->p2p)
return -EIO;
ret = iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD,
- true);
+ true, NULL);
if (ret)
return ret;
}
int iwl_mvm_mac_ctxt_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- bool force_assoc_off)
+ bool force_assoc_off, const u8 *bssid_override)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
return -EIO;
return iwl_mvm_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY,
- force_assoc_off);
+ force_assoc_off, bssid_override);
}
int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
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 */
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);
/* 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);
/* 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);
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 */
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;
}
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) {
if (!WARN_ON(!mvmsta))
iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, true);
- iwl_mvm_mac_ctxt_changed(mvm, vif, true);
+ iwl_mvm_mac_ctxt_changed(mvm, vif, true, NULL);
break;
default:
break;