Commit 689a5e6f authored by Seevalamuthu Mariappan's avatar Seevalamuthu Mariappan Committed by Kalle Valo
Browse files

ath11k: monitor mode clean up to use separate APIs



If monitor interface is enabled in co-exist mode, only local traffic are
captured. It's caused by missing monitor vdev in co-exist mode. So,
monitor mode clean up is done with separate Monitor APIs. For this,
introduce flags monitor_started and monitor_vdev_created.

Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01725-QCAHKSWPL_SILICONZ-1

Co-developed-by: default avatarMiles Hu <milehu@codeaurora.org>
Signed-off-by: default avatarMiles Hu <milehu@codeaurora.org>
Co-developed-by: default avatarVasanthakumar Thiagarajan <vthiagar@codeaurora.org>
Signed-off-by: default avatarVasanthakumar Thiagarajan <vthiagar@codeaurora.org>
Signed-off-by: default avatarSeevalamuthu Mariappan <seevalam@codeaurora.org>
Signed-off-by: default avatarJouni Malinen <jouni@codeaurora.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20210721162053.46290-4-jouni@codeaurora.org
parent 64e06b78
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -193,7 +193,6 @@ enum ath11k_dev_flags {
};

enum ath11k_monitor_flags {
	ATH11K_FLAG_MONITOR_ENABLED,
	ATH11K_FLAG_MONITOR_CONF_ENABLED,
	ATH11K_FLAG_MONITOR_STARTED,
	ATH11K_FLAG_MONITOR_VDEV_CREATED,
+1 −1
Original line number Diff line number Diff line
@@ -5029,7 +5029,7 @@ int ath11k_dp_rx_process_mon_rings(struct ath11k_base *ab, int mac_id,
	struct ath11k *ar = ath11k_ab_to_ar(ab, mac_id);
	int ret = 0;

	if (test_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags))
	if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags))
		ret = ath11k_dp_mon_process_rx(ab, mac_id, napi, budget);
	else
		ret = ath11k_dp_rx_process_mon_status(ab, mac_id, napi, budget);
+6 −2
Original line number Diff line number Diff line
@@ -1076,12 +1076,16 @@ int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset)

	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
		ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
		if (!reset)
		if (!reset) {
			tlv_filter.rx_filter =
					HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING;
		else
		} else {
			tlv_filter = ath11k_mac_mon_status_filter_default;

			if (ath11k_debugfs_is_extd_rx_stats_enabled(ar))
				tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar);
		}

		ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id,
						       dp->mac_id + i,
						       HAL_RXDMA_MONITOR_STATUS,
+103 −47
Original line number Diff line number Diff line
@@ -715,22 +715,6 @@ void ath11k_mac_peer_cleanup_all(struct ath11k *ar)
	ar->num_stations = 0;
}

static int ath11k_monitor_vdev_up(struct ath11k *ar, int vdev_id)
{
	int ret = 0;

	ret = ath11k_wmi_vdev_up(ar, vdev_id, 0, ar->mac_addr);
	if (ret) {
		ath11k_warn(ar->ab, "failed to put up monitor vdev %i: %d\n",
			    vdev_id, ret);
		return ret;
	}

	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac monitor vdev %i started\n",
		   vdev_id);
	return 0;
}

static inline int ath11k_mac_vdev_setup_sync(struct ath11k *ar)
{
	lockdep_assert_held(&ar->conf_mutex);
@@ -2326,7 +2310,7 @@ static int ath11k_mac_config_obss_pd(struct ath11k *ar,

	/* Set and enable SRG/non-SRG OBSS PD Threshold */
	param_id = WMI_PDEV_PARAM_SET_CMD_OBSS_PD_THRESHOLD;
	if (test_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags)) {
	if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) {
		ret = ath11k_wmi_pdev_set_param(ar, param_id, 0, pdev_id);
		if (ret)
			ath11k_warn(ar->ab,
@@ -5100,8 +5084,8 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
	}

	if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) {
		ath11k_warn(ab, "failed to create vdev, reached max vdev limit %d\n",
			    TARGET_NUM_VDEVS);
		ath11k_warn(ab, "failed to create vdev %u, reached max vdev limit %d\n",
			    ar->num_created_vdevs, TARGET_NUM_VDEVS);
		ret = -EBUSY;
		goto err;
	}
@@ -5141,6 +5125,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
		break;
	case NL80211_IFTYPE_MONITOR:
		arvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
		ar->monitor_vdev_id = bit;
		break;
	default:
		WARN_ON(1);
@@ -5242,6 +5227,9 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
			goto err_peer_del;
		}
		break;
	case WMI_VDEV_TYPE_MONITOR:
		set_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags);
		break;
	default:
		break;
	}
@@ -5262,6 +5250,16 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,

	ath11k_dp_vdev_tx_attach(ar, arvif);

	if (vif->type != NL80211_IFTYPE_MONITOR &&
	    test_bit(ATH11K_FLAG_MONITOR_CONF_ENABLED, &ar->monitor_flags)) {
		ret = ath11k_mac_monitor_vdev_create(ar);
		if (ret) {
			ath11k_warn(ar->ab, "failed to create monitor vdev during add interface: %d",
				    ret);
			goto err_peer_del;
		}
	}

	mutex_unlock(&ar->conf_mutex);

	return 0;
@@ -5359,6 +5357,18 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,
	ath11k_dbg(ab, ATH11K_DBG_MAC, "vdev %pM deleted, vdev_id %d\n",
		   vif->addr, arvif->vdev_id);

	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
		clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags);
		ar->monitor_vdev_id = -1;
	} else if (test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags) &&
		   !test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) {
		ret = ath11k_mac_monitor_vdev_delete(ar);
		if (ret)
			/* continue even if there's an error */
			ath11k_warn(ar->ab, "failed to delete vdev monitor during remove interface: %d",
				    ret);
	}

err_vdev_del:
	spin_lock_bh(&ar->data_lock);
	list_del(&arvif->list);
@@ -5378,7 +5388,6 @@ static void ath11k_mac_op_remove_interface(struct ieee80211_hw *hw,

	/* Recalc txpower for remaining vdev */
	ath11k_mac_txpower_recalc(ar);
	clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);

	/* TODO: recal traffic pause state based on the available vdevs */

@@ -5401,8 +5410,6 @@ static void ath11k_mac_op_configure_filter(struct ieee80211_hw *hw,
					   u64 multicast)
{
	struct ath11k *ar = hw->priv;
	bool reset_flag = false;
	int ret = 0;

	mutex_lock(&ar->conf_mutex);

@@ -5410,23 +5417,6 @@ static void ath11k_mac_op_configure_filter(struct ieee80211_hw *hw,
	*total_flags &= SUPPORTED_FILTERS;
	ar->filter_flags = *total_flags;

	/* For monitor mode */
	reset_flag = !(ar->filter_flags & FIF_BCN_PRBRESP_PROMISC);

	ret = ath11k_dp_tx_htt_monitor_mode_ring_config(ar, reset_flag);
	if (!ret) {
		if (!reset_flag)
			set_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
		else
			clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
	} else {
		ath11k_warn(ar->ab,
			    "fail to set monitor filter: %d\n", ret);
	}
	ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
		   "changed_flags:0x%x, total_flags:0x%x, reset_flag:%d\n",
		   changed_flags, *total_flags, reset_flag);

	mutex_unlock(&ar->conf_mutex);
}

@@ -5617,7 +5607,9 @@ ath11k_mac_vdev_start_restart(struct ath11k_vif *arvif,
		return ret;
	}

	if (!restart)
		ar->num_started_vdevs++;

	ath11k_dbg(ab, ATH11K_DBG_MAC,  "vdev %pM started, vdev_id %d\n",
		   arvif->vif->addr, arvif->vdev_id);

@@ -5745,12 +5737,16 @@ ath11k_mac_update_vif_chan(struct ath11k *ar,
	struct ath11k_vif *arvif;
	int ret;
	int i;
	bool monitor_vif = false;

	lockdep_assert_held(&ar->conf_mutex);

	for (i = 0; i < n_vifs; i++) {
		arvif = (void *)vifs[i].vif->drv_priv;

		if (vifs[i].vif->type == NL80211_IFTYPE_MONITOR)
			monitor_vif = true;

		ath11k_dbg(ab, ATH11K_DBG_MAC,
			   "mac chanctx switch vdev_id %i freq %u->%u width %d->%d\n",
			   arvif->vdev_id,
@@ -5771,6 +5767,8 @@ ath11k_mac_update_vif_chan(struct ath11k *ar,
				    arvif->vdev_id, ret);
			continue;
		}

		ar->num_started_vdevs--;
	}

	/* All relevant vdevs are downed and associated channel resources
@@ -5808,6 +5806,24 @@ ath11k_mac_update_vif_chan(struct ath11k *ar,
			continue;
		}
	}

	/* Restart the internal monitor vdev on new channel */
	if (!monitor_vif &&
	    test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) {
		ret = ath11k_mac_monitor_stop(ar);
		if (ret) {
			ath11k_warn(ar->ab, "failed to stop monitor during vif channel update: %d",
				    ret);
			return;
		}

		ret = ath11k_mac_monitor_start(ar);
		if (ret) {
			ath11k_warn(ar->ab, "failed to start monitor during vif channel update: %d",
				    ret);
			return;
		}
	}
}

static void
@@ -5887,7 +5903,7 @@ static int ath11k_start_vdev_delay(struct ieee80211_hw *hw,
	}

	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
		ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id);
		ret = ath11k_wmi_vdev_up(ar, arvif->vdev_id, 0, ar->mac_addr);
		if (ret) {
			ath11k_warn(ab, "failed put monitor up: %d\n", ret);
			return ret;
@@ -5947,6 +5963,18 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
		}
	}

	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
		ret = ath11k_mac_monitor_start(ar);
		if (ret) {
			ath11k_warn(ar->ab, "failed to start monitor during vif channel context assignment: %d",
				    ret);
			goto out;
		}

		arvif->is_started = true;
		goto out;
	}

	ret = ath11k_mac_vdev_start(arvif, &ctx->def);
	if (ret) {
		ath11k_warn(ab, "failed to start vdev %i addr %pM on freq %d: %d\n",
@@ -5954,14 +5982,19 @@ ath11k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
			    ctx->def.chan->center_freq, ret);
		goto out;
	}
	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
		ret = ath11k_monitor_vdev_up(ar, arvif->vdev_id);
		if (ret)
			goto out;
	}

	arvif->is_started = true;

	if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
	    test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) {
		ret = ath11k_mac_monitor_start(ar);
		if (ret) {
			ath11k_warn(ar->ab, "failed to start monitor during vif channel context assignment: %d",
				    ret);
			goto out;
		}
	}

	/* TODO: Setup ps and cts/rts protection */

	ret = 0;
@@ -5995,6 +6028,20 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
	    ath11k_peer_find_by_addr(ab, ar->mac_addr))
		ath11k_peer_delete(ar, arvif->vdev_id, ar->mac_addr);

	if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
		ret = ath11k_mac_monitor_stop(ar);
		if (ret) {
			ath11k_warn(ar->ab, "failed to stop monitor during vif channel context unassignment: %d",
				    ret);
			mutex_unlock(&ar->conf_mutex);
			return;
		}

		arvif->is_started = false;
		mutex_unlock(&ar->conf_mutex);
		return;
	}

	ret = ath11k_mac_vdev_stop(arvif);
	if (ret)
		ath11k_warn(ab, "failed to stop vdev %i: %d\n",
@@ -6006,6 +6053,16 @@ ath11k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
	    arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
		ath11k_wmi_vdev_down(ar, arvif->vdev_id);

	if (arvif->vdev_type != WMI_VDEV_TYPE_MONITOR &&
	    ar->num_started_vdevs == 1 &&
	    test_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags)) {
		ret = ath11k_mac_monitor_stop(ar);
		if (ret)
			/* continue even if there's an error */
			ath11k_warn(ar->ab, "failed to stop monitor during vif channel context unassignment: %d",
				    ret);
	}

	mutex_unlock(&ar->conf_mutex);
}

@@ -7128,7 +7185,6 @@ int ath11k_mac_allocate(struct ath11k_base *ab)
		INIT_WORK(&ar->wmi_mgmt_tx_work, ath11k_mgmt_over_wmi_tx_work);
		skb_queue_head_init(&ar->wmi_mgmt_tx_queue);

		clear_bit(ATH11K_FLAG_MONITOR_ENABLED, &ar->monitor_flags);
		clear_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags);

		ar->monitor_vdev_id = -1;