Commit cc3ba78f authored by Benjamin Berg's avatar Benjamin Berg Committed by Johannes Berg
Browse files

wifi: iwlwifi: mvm: remove stale STA link data during restart



If pre-recovery mac80211 tried to disable a link but this disablement
failed, then there might be a mismatch between mac80211 assuming the
link has been disabled and the driver still having the data around.
During recover itself, that is not a problem, but should the link be
activated again at a later point, iwlwifi will refuse the activation as
it detects the inconsistent state.

Solve this corner-case by iterating the station in the restart cleanup
handler.

Signed-off-by: default avatarBenjamin Berg <benjamin.berg@intel.com>
Signed-off-by: default avatarMiri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://msgid.link/20240513132416.d2fd60338055.I840d4fdce5fd49fe69896d928b071067e3730259@changeid


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 87821b67
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -1128,6 +1128,39 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
	RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL);
}

static void iwl_mvm_cleanup_sta_iterator(void *data, struct ieee80211_sta *sta)
{
	struct iwl_mvm *mvm = data;
	struct iwl_mvm_sta *mvm_sta;
	struct ieee80211_vif *vif;
	int link_id;

	mvm_sta = iwl_mvm_sta_from_mac80211(sta);
	vif = mvm_sta->vif;

	if (!sta->valid_links)
		return;

	for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) {
		struct iwl_mvm_link_sta *mvm_link_sta;

		mvm_link_sta =
			rcu_dereference_check(mvm_sta->link[link_id],
					      lockdep_is_held(&mvm->mutex));
		if (mvm_link_sta && !(vif->active_links & BIT(link_id))) {
			/*
			 * We have a link STA but the link is inactive in
			 * mac80211. This will happen if we failed to
			 * deactivate the link but mac80211 roll back the
			 * deactivation of the link.
			 * Delete the stale data to avoid issues later on.
			 */
			iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_link_sta,
						  link_id, false);
		}
	}
}

static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
{
	iwl_mvm_stop_device(mvm);
@@ -1150,6 +1183,10 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
	 */
	ieee80211_iterate_interfaces(mvm->hw, 0, iwl_mvm_cleanup_iterator, mvm);

	/* cleanup stations as links may be gone after restart */
	ieee80211_iterate_stations_atomic(mvm->hw,
					  iwl_mvm_cleanup_sta_iterator, mvm);

	mvm->p2p_device_vif = NULL;

	iwl_mvm_reset_phy_ctxts(mvm);
+5 −5
Original line number Diff line number Diff line
@@ -515,7 +515,7 @@ static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
	return iwl_mvm_mld_send_sta_cmd(mvm, &cmd);
}

static void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,
void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,
			       struct iwl_mvm_sta *mvm_sta,
			       struct iwl_mvm_link_sta *mvm_sta_link,
			       unsigned int link_id,
+5 −0
Original line number Diff line number Diff line
@@ -662,6 +662,11 @@ int iwl_mvm_mld_update_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
			   struct ieee80211_sta *sta);
int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
		       struct ieee80211_sta *sta);
void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,
			       struct iwl_mvm_sta *mvm_sta,
			       struct iwl_mvm_link_sta *mvm_sta_link,
			       unsigned int link_id,
			       bool is_in_fw);
int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id);
int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
				 struct ieee80211_vif *vif,