Commit 1933747f authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo
Browse files

ath10k: fix monitor start/stop sequences



Fix some cases where monitor start failure left
the driver in a confused state.

This also makes the monitor code simpler.

Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 21396271
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -472,7 +472,6 @@ struct ath10k {
	struct cfg80211_chan_def chandef;

	int free_vdev_map;
	bool promisc;
	bool monitor;
	int monitor_vdev_id;
	bool monitor_started;
+49 −72
Original line number Diff line number Diff line
@@ -493,19 +493,6 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
	return 0;
}

static bool ath10k_monitor_is_enabled(struct ath10k *ar)
{
	lockdep_assert_held(&ar->conf_mutex);

	ath10k_dbg(ar, ATH10K_DBG_MAC,
		   "mac monitor refs: promisc %d monitor %d cac %d\n",
		   ar->promisc, ar->monitor,
		   test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags));

	return ar->promisc || ar->monitor ||
	       test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
}

static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
{
	struct cfg80211_chan_def *chandef = &ar->chandef;
@@ -649,16 +636,6 @@ static int ath10k_monitor_start(struct ath10k *ar)

	lockdep_assert_held(&ar->conf_mutex);

	if (!ath10k_monitor_is_enabled(ar)) {
		ath10k_warn(ar, "trying to start monitor with no references\n");
		return 0;
	}

	if (ar->monitor_started) {
		ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor already started\n");
		return 0;
	}

	ret = ath10k_monitor_vdev_create(ar);
	if (ret) {
		ath10k_warn(ar, "failed to create monitor vdev: %d\n", ret);
@@ -678,34 +655,51 @@ static int ath10k_monitor_start(struct ath10k *ar)
	return 0;
}

static void ath10k_monitor_stop(struct ath10k *ar)
static int ath10k_monitor_stop(struct ath10k *ar)
{
	int ret;

	lockdep_assert_held(&ar->conf_mutex);

	if (ath10k_monitor_is_enabled(ar)) {
		ath10k_dbg(ar, ATH10K_DBG_MAC,
			   "mac monitor will be stopped later\n");
		return;
	}

	if (!ar->monitor_started) {
		ath10k_dbg(ar, ATH10K_DBG_MAC,
			   "mac monitor probably failed to start earlier\n");
		return;
	}

	ret = ath10k_monitor_vdev_stop(ar);
	if (ret)
	if (ret) {
		ath10k_warn(ar, "failed to stop monitor vdev: %d\n", ret);
		return ret;
	}

	ret = ath10k_monitor_vdev_delete(ar);
	if (ret)
	if (ret) {
		ath10k_warn(ar, "failed to delete monitor vdev: %d\n", ret);
		return ret;
	}

	ar->monitor_started = false;
	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor stopped\n");

	return 0;
}

static int ath10k_monitor_recalc(struct ath10k *ar)
{
	bool should_start;

	lockdep_assert_held(&ar->conf_mutex);

	should_start = ar->monitor ||
		       ar->filter_flags & FIF_PROMISC_IN_BSS ||
		       test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);

	ath10k_dbg(ar, ATH10K_DBG_MAC,
		   "mac monitor recalc started? %d should? %d\n",
		   ar->monitor_started, should_start);

	if (should_start == ar->monitor_started)
		return 0;

	if (should_start)
		return ath10k_monitor_start(ar);
	else
		return ath10k_monitor_stop(ar);
}

static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
@@ -736,7 +730,7 @@ static int ath10k_start_cac(struct ath10k *ar)

	set_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);

	ret = ath10k_monitor_start(ar);
	ret = ath10k_monitor_recalc(ar);
	if (ret) {
		ath10k_warn(ar, "failed to start monitor (cac): %d\n", ret);
		clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
@@ -2369,12 +2363,14 @@ void ath10k_halt(struct ath10k *ar)

	lockdep_assert_held(&ar->conf_mutex);

	if (ath10k_monitor_is_enabled(ar)) {
	clear_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
		ar->promisc = false;
	ar->filter_flags = 0;
	ar->monitor = false;

	if (ar->monitor_started)
		ath10k_monitor_stop(ar);
	}

	ar->monitor_started = false;

	ath10k_scan_finish(ar);
	ath10k_peer_cleanup_all(ar);
@@ -2629,7 +2625,7 @@ static void ath10k_config_chan(struct ath10k *ar)
	/* First stop monitor interface. Some FW versions crash if there's a
	 * lone monitor interface. */
	if (ar->monitor_started)
		ath10k_monitor_vdev_stop(ar);
		ath10k_monitor_stop(ar);

	list_for_each_entry(arvif, &ar->arvifs, list) {
		if (!arvif->is_started)
@@ -2677,8 +2673,7 @@ static void ath10k_config_chan(struct ath10k *ar)
		}
	}

	if (ath10k_monitor_is_enabled(ar))
		ath10k_monitor_vdev_start(ar, ar->monitor_vdev_id);
	ath10k_monitor_recalc(ar);
}

static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
@@ -2733,19 +2728,10 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
		ath10k_config_ps(ar);

	if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
		if (conf->flags & IEEE80211_CONF_MONITOR && !ar->monitor) {
			ar->monitor = true;
			ret = ath10k_monitor_start(ar);
			if (ret) {
				ath10k_warn(ar, "failed to start monitor (config): %d\n",
					    ret);
				ar->monitor = false;
			}
		} else if (!(conf->flags & IEEE80211_CONF_MONITOR) &&
			   ar->monitor) {
			ar->monitor = false;
			ath10k_monitor_stop(ar);
		}
		ar->monitor = conf->flags & IEEE80211_CONF_MONITOR;
		ret = ath10k_monitor_recalc(ar);
		if (ret)
			ath10k_warn(ar, "failed to recalc monitor: %d\n", ret);
	}

	mutex_unlock(&ar->conf_mutex);
@@ -3009,18 +2995,9 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,
	*total_flags &= SUPPORTED_FILTERS;
	ar->filter_flags = *total_flags;

	if (ar->filter_flags & FIF_PROMISC_IN_BSS && !ar->promisc) {
		ar->promisc = true;
		ret = ath10k_monitor_start(ar);
		if (ret) {
			ath10k_warn(ar, "failed to start monitor (promisc): %d\n",
				    ret);
			ar->promisc = false;
		}
	} else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) && ar->promisc) {
		ar->promisc = false;
		ath10k_monitor_stop(ar);
	}
	ret = ath10k_monitor_recalc(ar);
	if (ret)
		ath10k_warn(ar, "failed to recalc montior: %d\n", ret);

	mutex_unlock(&ar->conf_mutex);
}