Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68b99311 authored by Garen Tamrazian's avatar Garen Tamrazian Committed by Wey-Yi Guy
Browse files

iwlagn: fix radar frame rejection



The microcode may sometimes reject TX frames when
on a radar channel even after we associated as it
clears information during association and needs to
receive a new beacon before allowing that channel
again. This manifests itself as a TX status value
of TX_STATUS_FAIL_PASSIVE_NO_RX. So in this case,
stop the corresponding queue and give the frame
back to mac80211 for retransmission. We start the
queue again when a beacon from the AP is received
which will make the regulatory enforcement in the
device allow transmitting again.

Signed-off-by: default avatarGaren Tamrazian <garenx.tamrazian@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
parent 3ecccbcd
Loading
Loading
Loading
Loading
+21 −8
Original line number Diff line number Diff line
@@ -172,6 +172,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)

static void iwlagn_set_tx_status(struct iwl_priv *priv,
				 struct ieee80211_tx_info *info,
				 struct iwl_rxon_context *ctx,
				 struct iwlagn_tx_resp *tx_resp,
				 int txq_id, bool is_agg)
{
@@ -186,6 +187,13 @@ static void iwlagn_set_tx_status(struct iwl_priv *priv,
	if (!iwl_is_tx_success(status))
		iwlagn_count_tx_err_status(priv, status);

	if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
	    iwl_is_associated_ctx(ctx) && ctx->vif &&
	    ctx->vif->type == NL80211_IFTYPE_STATION) {
		ctx->last_tx_rejected = true;
		iwl_stop_queue(priv, &priv->txq[txq_id]);
	}

	IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags "
			   "0x%x retries %d\n",
			   txq_id,
@@ -242,15 +250,16 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,

	/* # frames attempted by Tx command */
	if (agg->frame_count == 1) {
		struct iwl_tx_info *txb;

		/* Only one frame was attempted; no block-ack will arrive */
		idx = start_idx;

		IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
				   agg->frame_count, agg->start_idx, idx);
		iwlagn_set_tx_status(priv,
				     IEEE80211_SKB_CB(
					priv->txq[txq_id].txb[idx].skb),
				     tx_resp, txq_id, true);
		txb = &priv->txq[txq_id].txb[idx];
		iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(txb->skb),
				     txb->ctx, tx_resp, txq_id, true);
		agg->wait_for_ba = 0;
	} else {
		/* Two or more frames were attempted; expect block-ack */
@@ -391,6 +400,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
	struct iwl_tx_queue *txq = &priv->txq[txq_id];
	struct ieee80211_tx_info *info;
	struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
	struct iwl_tx_info *txb;
	u32 status = le16_to_cpu(tx_resp->status.status);
	int tid;
	int sta_id;
@@ -406,7 +416,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
	}

	txq->time_stamp = jiffies;
	info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
	txb = &txq->txb[txq->q.read_ptr];
	info = IEEE80211_SKB_CB(txb->skb);
	memset(&info->status, 0, sizeof(info->status));

	tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
@@ -450,12 +461,14 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
				iwl_wake_queue(priv, txq);
		}
	} else {
		iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false);
		iwlagn_set_tx_status(priv, info, txb->ctx, tx_resp,
				     txq_id, false);
		freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
		iwl_free_tfds_in_queue(priv, sta_id, tid, freed);

		if (priv->mac80211_registered &&
		    (iwl_queue_space(&txq->q) > txq->q.low_mark))
		    iwl_queue_space(&txq->q) > txq->q.low_mark &&
		    status != TX_STATUS_FAIL_PASSIVE_NO_RX)
			iwl_wake_queue(priv, txq);
	}

+13 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include "iwl-sta.h"
#include "iwl-core.h"
#include "iwl-agn-calib.h"
#include "iwl-helpers.h"

static int iwlagn_disable_bss(struct iwl_priv *priv,
			      struct iwl_rxon_context *ctx,
@@ -600,6 +601,18 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
			priv->timestamp = bss_conf->timestamp;
			ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
		} else {
			/*
			 * If we disassociate while there are pending
			 * frames, just wake up the queues and let the
			 * frames "escape" ... This shouldn't really
			 * be happening to start with, but we should
			 * not get stuck in this case either since it
			 * can happen if userspace gets confused.
			 */
			if (ctx->last_tx_rejected) {
				ctx->last_tx_rejected = false;
				iwl_wake_any_queue(priv, ctx);
			}
			ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
		}
	}
+3 −0
Original line number Diff line number Diff line
@@ -428,6 +428,7 @@ void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
int iwlagn_alive_notify(struct iwl_priv *priv)
{
	const struct queue_to_fifo_ac *queue_to_fifo;
	struct iwl_rxon_context *ctx;
	u32 a;
	unsigned long flags;
	int i, chan;
@@ -501,6 +502,8 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
	memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
	for (i = 0; i < 4; i++)
		atomic_set(&priv->queue_stop_count[i], 0);
	for_each_context(priv, ctx)
		ctx->last_tx_rejected = false;

	/* reset to 0 to enable all the queue first */
	priv->txq_ctx_active_msk = 0;
+1 −0
Original line number Diff line number Diff line
@@ -220,6 +220,7 @@ static inline u32 iwl_tx_status_to_mac80211(u32 status)
	case TX_STATUS_DIRECT_DONE:
		return IEEE80211_TX_STAT_ACK;
	case TX_STATUS_FAIL_DEST_PS:
	case TX_STATUS_FAIL_PASSIVE_NO_RX:
		return IEEE80211_TX_STAT_TX_FILTERED;
	default:
		return 0;
+2 −0
Original line number Diff line number Diff line
@@ -1170,6 +1170,8 @@ struct iwl_rxon_context {
		bool enabled, is_40mhz;
		u8 extension_chan_offset;
	} ht;

	bool last_tx_rejected;
};

enum iwl_scan_type {
Loading