Linux wireless drivers development
 help / color / mirror / Atom feed
* [RFT 8/9] ath9k: handle low buffer space for virtual wiphys
From: Luis R. Rodriguez @ 2009-11-03  3:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: ath9k-devel, Luis R. Rodriguez, Jouni.Malinen
In-Reply-To: <1257217681-27180-1-git-send-email-lrodriguez@atheros.com>

ath9k virtual wiphys all share the same internal buffer space
for TX but they do not share the mac80211 skb queues. When
ath9k detects it is running low on buffer space to TX it tells
mac80211 to stop sending it skbs its way but it always does
this only for the primary wiphy. This means mac80211 won't know
its best to avoid sending ath9k more skbs on a separate virtual
wiphy. The same issue is present for reliving the skb queue.

Since ath9k does not keep track of which virtual wiphy is hammering
on TX silence all wiphy's TX when we're low on buffer space. When
we're free on buffer space only bother informing the virtual wiphy
which is active that we have free buffers.

Cc: Jouni.Malinen <Jouni.Malinen@atheros.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/ath9k.h   |    3 ++
 drivers/net/wireless/ath/ath9k/virtual.c |   52 ++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/xmit.c    |   10 +++---
 3 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 59ce7ec..4169d2b 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -695,5 +695,8 @@ void ath9k_wiphy_work(struct work_struct *work);
 bool ath9k_all_wiphys_idle(struct ath_softc *sc);
 void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle);
 
+void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue);
+void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue);
+
 int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
 #endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index 69a871b..0a36b57 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -697,3 +697,55 @@ void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle)
 		  wiphy_name(aphy->hw->wiphy),
 		  idle ? "idle" : "not-idle");
 }
+/* Only bother starting a queue on an active virtual wiphy */
+void ath_mac80211_start_queue(struct ath_softc *sc, u16 skb_queue)
+{
+	struct ieee80211_hw *hw = sc->pri_wiphy->hw;
+	unsigned int i;
+
+	spin_lock_bh(&sc->wiphy_lock);
+
+	/* Start the primary wiphy */
+	if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE) {
+		ieee80211_wake_queue(hw, skb_queue);
+		goto unlock;
+	}
+
+	/* Now start the secondary wiphy queues */
+	for (i = 0; i < sc->num_sec_wiphy; i++) {
+		struct ath_wiphy *aphy = sc->sec_wiphy[i];
+		if (!aphy)
+			continue;
+		if (aphy->state != ATH_WIPHY_ACTIVE)
+			continue;
+
+		hw = aphy->hw;
+		ieee80211_wake_queue(hw, skb_queue);
+		break;
+	}
+
+unlock:
+	spin_unlock_bh(&sc->wiphy_lock);
+}
+
+/* Go ahead and propagate information to all virtual wiphys, it won't hurt */
+void ath_mac80211_stop_queue(struct ath_softc *sc, u16 skb_queue)
+{
+	struct ieee80211_hw *hw = sc->pri_wiphy->hw;
+	unsigned int i;
+
+	spin_lock_bh(&sc->wiphy_lock);
+
+	/* Stop the primary wiphy */
+	ieee80211_stop_queue(hw, skb_queue);
+
+	/* Now stop the secondary wiphy queues */
+	for (i = 0; i < sc->num_sec_wiphy; i++) {
+		struct ath_wiphy *aphy = sc->sec_wiphy[i];
+		if (!aphy)
+			continue;
+		hw = aphy->hw;
+		ieee80211_stop_queue(hw, skb_queue);
+	}
+	spin_unlock_bh(&sc->wiphy_lock);
+}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 427bd1d..40d34ed 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -914,9 +914,10 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
 struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
 {
 	struct ath_txq *txq = NULL;
+	u16 skb_queue = skb_get_queue_mapping(skb);
 	int qnum;
 
-	qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
+	qnum = ath_get_hal_qnum(skb_queue, sc);
 	txq = &sc->tx.txq[qnum];
 
 	spin_lock_bh(&txq->axq_lock);
@@ -925,7 +926,7 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
 		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT,
 			  "TX queue: %d is full, depth: %d\n",
 			  qnum, txq->axq_depth);
-		ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb));
+		ath_mac80211_stop_queue(sc, skb_queue);
 		txq->stopped = 1;
 		spin_unlock_bh(&txq->axq_lock);
 		return NULL;
@@ -1704,8 +1705,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 		 * on the queue */
 		spin_lock_bh(&txq->axq_lock);
 		if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) {
-			ieee80211_stop_queue(sc->hw,
-				skb_get_queue_mapping(skb));
+			ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
 			txq->stopped = 1;
 		}
 		spin_unlock_bh(&txq->axq_lock);
@@ -1945,7 +1945,7 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
 	    sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) {
 		qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);
 		if (qnum != -1) {
-			ieee80211_wake_queue(sc->hw, qnum);
+			ath_mac80211_start_queue(sc, qnum);
 			txq->stopped = 0;
 		}
 	}
-- 
1.6.5.2.143.g8cc62


^ permalink raw reply related

* [RFT 4/9] ath9k: use the passed ieee80211_hw on ath_rx_prepare()
From: Luis R. Rodriguez @ 2009-11-03  3:07 UTC (permalink / raw)
  To: linux-wireless; +Cc: ath9k-devel, Luis R. Rodriguez, Jouni.Malinen
In-Reply-To: <1257217681-27180-1-git-send-email-lrodriguez@atheros.com>

this now uses the proper hw which should mean finding the
right sta when using ath9k virtual wiphy stuff.

Cc: Jouni.Malinen <Jouni.Malinen@atheros.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/recv.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 330cd3b..10decfa 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -200,7 +200,7 @@ static int ath_rx_prepare(struct ieee80211_hw *hw,
 	}
 
 	rcu_read_lock();
-	sta = ieee80211_find_sta(sc->hw, hdr->addr2);
+	sta = ieee80211_find_sta(hw, hdr->addr2);
 	if (sta) {
 		an = (struct ath_node *) sta->drv_priv;
 		if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
-- 
1.6.5.2.143.g8cc62


^ permalink raw reply related

* [RFT 7/9] ath9k: use the right hw on ath_tx_setup_buffer() for HT
From: Luis R. Rodriguez @ 2009-11-03  3:07 UTC (permalink / raw)
  To: linux-wireless; +Cc: ath9k-devel, Luis R. Rodriguez, Jouni.Malinen
In-Reply-To: <1257217681-27180-1-git-send-email-lrodriguez@atheros.com>

When using virtual wiphys the base sc->hw was being used, the correct
hw is passed along the caller already so just use that.

Cc: Jouni.Malinen <Jouni.Malinen@atheros.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/xmit.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 5d0851b..427bd1d 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1575,7 +1575,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
 
 	bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
 
-	if (conf_is_ht(&sc->hw->conf) && !is_pae(skb))
+	if (conf_is_ht(&hw->conf) && !is_pae(skb))
 		bf->bf_state.bf_type |= BUF_HT;
 
 	bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq);
-- 
1.6.5.2.143.g8cc62


^ permalink raw reply related

* [RFT 9/9] ath9k: do not pass the entire descriptor to ath_rx_prepare()
From: Luis R. Rodriguez @ 2009-11-03  3:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: ath9k-devel, Luis R. Rodriguez
In-Reply-To: <1257217681-27180-1-git-send-email-lrodriguez@atheros.com>

Its not needed, so just pass the hardware RX status.
We'll be simplfying ath_rx_prepare() with code we can share
between ath9k and ath9k_htc. This will help make that code
easier to read and manage.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/recv.c |   70 +++++++++++++++++----------------
 1 files changed, 36 insertions(+), 34 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 10decfa..b36ecb2 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -106,7 +106,7 @@ static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
  * decryption key or real decryption error. This let us keep statistics there.
  */
 static int ath_rx_prepare(struct ieee80211_hw *hw,
-			  struct sk_buff *skb, struct ath_desc *ds,
+			  struct sk_buff *skb, struct ath_rx_status *rxstats,
 			  struct ieee80211_rx_status *rx_status, bool *decrypt_error,
 			  struct ath_softc *sc)
 {
@@ -121,7 +121,7 @@ static int ath_rx_prepare(struct ieee80211_hw *hw,
 	fc = hdr->frame_control;
 	memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
 
-	if (ds->ds_rxstat.rs_more) {
+	if (rxstats->rs_more) {
 		/*
 		 * Frame spans multiple descriptors; this cannot happen yet
 		 * as we don't support jumbograms. If not in monitor mode,
@@ -130,22 +130,22 @@ static int ath_rx_prepare(struct ieee80211_hw *hw,
 		 */
 		if (sc->sc_ah->opmode != NL80211_IFTYPE_MONITOR)
 			goto rx_next;
-	} else if (ds->ds_rxstat.rs_status != 0) {
-		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC)
+	} else if (rxstats->rs_status != 0) {
+		if (rxstats->rs_status & ATH9K_RXERR_CRC)
 			rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
-		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY)
+		if (rxstats->rs_status & ATH9K_RXERR_PHY)
 			goto rx_next;
 
-		if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) {
+		if (rxstats->rs_status & ATH9K_RXERR_DECRYPT) {
 			*decrypt_error = true;
-		} else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) {
+		} else if (rxstats->rs_status & ATH9K_RXERR_MIC) {
 			if (ieee80211_is_ctl(fc))
 				/*
 				 * Sometimes, we get invalid
 				 * MIC failures on valid control frames.
 				 * Remove these mic errors.
 				 */
-				ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC;
+				rxstats->rs_status &= ~ATH9K_RXERR_MIC;
 			else
 				rx_status->flag |= RX_FLAG_MMIC_ERROR;
 		}
@@ -155,26 +155,26 @@ static int ath_rx_prepare(struct ieee80211_hw *hw,
 		 * we also ignore the CRC error.
 		 */
 		if (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR) {
-			if (ds->ds_rxstat.rs_status &
+			if (rxstats->rs_status &
 			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
 			      ATH9K_RXERR_CRC))
 				goto rx_next;
 		} else {
-			if (ds->ds_rxstat.rs_status &
+			if (rxstats->rs_status &
 			    ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
 				goto rx_next;
 			}
 		}
 	}
 
-	ratecode = ds->ds_rxstat.rs_rate;
+	ratecode = rxstats->rs_rate;
 
 	if (ratecode & 0x80) {
 		/* HT rate */
 		rx_status->flag |= RX_FLAG_HT;
-		if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040)
+		if (rxstats->rs_flags & ATH9K_RX_2040)
 			rx_status->flag |= RX_FLAG_40MHZ;
-		if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI)
+		if (rxstats->rs_flags & ATH9K_RX_GI)
 			rx_status->flag |= RX_FLAG_SHORT_GI;
 		rx_status->rate_idx = ratecode & 0x7f;
 	} else {
@@ -203,31 +203,31 @@ static int ath_rx_prepare(struct ieee80211_hw *hw,
 	sta = ieee80211_find_sta(hw, hdr->addr2);
 	if (sta) {
 		an = (struct ath_node *) sta->drv_priv;
-		if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
-		   !ds->ds_rxstat.rs_moreaggr)
-			ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi);
+		if (rxstats->rs_rssi != ATH9K_RSSI_BAD &&
+		   !rxstats->rs_moreaggr)
+			ATH_RSSI_LPF(an->last_rssi, rxstats->rs_rssi);
 		last_rssi = an->last_rssi;
 	}
 	rcu_read_unlock();
 
 	if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
-		ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi,
-					ATH_RSSI_EP_MULTIPLIER);
-	if (ds->ds_rxstat.rs_rssi < 0)
-		ds->ds_rxstat.rs_rssi = 0;
-	else if (ds->ds_rxstat.rs_rssi > 127)
-		ds->ds_rxstat.rs_rssi = 127;
+		rxstats->rs_rssi = ATH_EP_RND(last_rssi,
+					      ATH_RSSI_EP_MULTIPLIER);
+	if (rxstats->rs_rssi < 0)
+		rxstats->rs_rssi = 0;
+	else if (rxstats->rs_rssi > 127)
+		rxstats->rs_rssi = 127;
 
 	/* Update Beacon RSSI, this is used by ANI. */
 	if (ieee80211_is_beacon(fc))
-		sc->sc_ah->stats.avgbrssi = ds->ds_rxstat.rs_rssi;
+		sc->sc_ah->stats.avgbrssi = rxstats->rs_rssi;
 
-	rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
+	rx_status->mactime = ath_extend_tsf(sc, rxstats->rs_tstamp);
 	rx_status->band = hw->conf.channel->band;
 	rx_status->freq = hw->conf.channel->center_freq;
 	rx_status->noise = sc->ani.noise_floor;
-	rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi;
-	rx_status->antenna = ds->ds_rxstat.rs_antenna;
+	rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rxstats->rs_rssi;
+	rx_status->antenna = rxstats->rs_antenna;
 
 	/*
 	 * Theory for reporting quality:
@@ -251,9 +251,9 @@ static int ath_rx_prepare(struct ieee80211_hw *hw,
 	 *
 	 */
 	if (conf_is_ht(&hw->conf))
-		rx_status->qual =  ds->ds_rxstat.rs_rssi * 100 / 45;
+		rx_status->qual =  rxstats->rs_rssi * 100 / 45;
 	else
-		rx_status->qual =  ds->ds_rxstat.rs_rssi * 100 / 35;
+		rx_status->qual =  rxstats->rs_rssi * 100 / 35;
 
 	/* rssi can be more than 45 though, anything above that
 	 * should be considered at 100% */
@@ -658,6 +658,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 
 	struct ath_buf *bf;
 	struct ath_desc *ds;
+	struct ath_rx_status *rxstats;
 	struct sk_buff *skb = NULL, *requeue_skb;
 	struct ieee80211_rx_status rx_status;
 	struct ath_hw *ah = sc->sc_ah;
@@ -749,6 +750,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 
 		hdr = (struct ieee80211_hdr *) skb->data;
 		hw = ath_get_virt_hw(sc, hdr);
+		rxstats = &ds->ds_rxstat;
 
 		/*
 		 * If we're asked to flush receive queue, directly
@@ -757,14 +759,14 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 		if (flush)
 			goto requeue;
 
-		if (!ds->ds_rxstat.rs_datalen)
+		if (!rxstats->rs_datalen)
 			goto requeue;
 
 		/* The status portion of the descriptor could get corrupted. */
-		if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen)
+		if (sc->rx.bufsize < rxstats->rs_datalen)
 			goto requeue;
 
-		if (!ath_rx_prepare(hw, skb, ds,
+		if (!ath_rx_prepare(hw, skb, rxstats,
 				    &rx_status, &decrypt_error, sc))
 			goto requeue;
 
@@ -784,7 +786,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 				 sc->rx.bufsize,
 				 DMA_FROM_DEVICE);
 
-		skb_put(skb, ds->ds_rxstat.rs_datalen);
+		skb_put(skb, rxstats->rs_datalen);
 
 		/* see if any padding is done by the hw and remove it */
 		hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -804,7 +806,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 			skb_pull(skb, padsize);
 		}
 
-		keyix = ds->ds_rxstat.rs_keyix;
+		keyix = rxstats->rs_keyix;
 
 		if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) {
 			rx_status.flag |= RX_FLAG_DECRYPTED;
@@ -844,7 +846,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 		 */
 		if (sc->rx.defant != ds->ds_rxstat.rs_antenna) {
 			if (++sc->rx.rxotherant >= 3)
-				ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna);
+				ath_setdefantenna(sc, rxstats->rs_antenna);
 		} else {
 			sc->rx.rxotherant = 0;
 		}
-- 
1.6.5.2.143.g8cc62


^ permalink raw reply related

* [RFT 2/9] ath9k: update hw configuration for virtual wiphys
From: Luis R. Rodriguez @ 2009-11-03  3:07 UTC (permalink / raw)
  To: linux-wireless; +Cc: ath9k-devel, Luis R. Rodriguez, Jouni.Malinen
In-Reply-To: <1257217681-27180-1-git-send-email-lrodriguez@atheros.com>

ath9k supports its own virtual wiphys. The hardware code
relies on the ieee80211_hw for the present interface but
with recent changes introduced the common->hw was never
updated and is required for virtual wiphys.

Cc: Jouni.Malinen <Jouni.Malinen@atheros.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/virtual.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index e6a50f3..7678c4a 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -298,6 +298,7 @@ static void ath9k_wiphy_unpause_channel(struct ath_softc *sc)
 void ath9k_wiphy_chan_work(struct work_struct *work)
 {
 	struct ath_softc *sc = container_of(work, struct ath_softc, chan_work);
+	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ath_wiphy *aphy = sc->next_wiphy;
 
 	if (aphy == NULL)
@@ -313,6 +314,10 @@ void ath9k_wiphy_chan_work(struct work_struct *work)
 	/* XXX: remove me eventually */
 	ath9k_update_ichannel(sc, aphy->hw,
 			      &sc->sc_ah->channels[sc->chan_idx]);
+
+	/* sync hw configuration for hw code */
+	common->hw = aphy->hw;
+
 	ath_update_chainmask(sc, sc->chan_is_ht);
 	if (ath_set_channel(sc, aphy->hw,
 			    &sc->sc_ah->channels[sc->chan_idx]) < 0) {
-- 
1.6.5.2.143.g8cc62


^ permalink raw reply related

* [RFT 6/9] ath9k: use correct hw for tx aggregation TX completion
From: Luis R. Rodriguez @ 2009-11-03  3:07 UTC (permalink / raw)
  To: linux-wireless; +Cc: ath9k-devel, Luis R. Rodriguez, Jouni.Malinen
In-Reply-To: <1257217681-27180-1-git-send-email-lrodriguez@atheros.com>

When ath9k virtual wiphys are used the sc->hw will not always represent
the active hw, instead we need to get it from the skb->cb private
driver area. This ensures the right hw is used to find a sta for
the TX'd skb.

Cc: Jouni.Malinen <Jouni.Malinen@atheros.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/xmit.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 2a4efcb..5d0851b 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -267,7 +267,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 	struct ath_node *an = NULL;
 	struct sk_buff *skb;
 	struct ieee80211_sta *sta;
+	struct ieee80211_hw *hw;
 	struct ieee80211_hdr *hdr;
+	struct ieee80211_tx_info *tx_info;
+	struct ath_tx_info_priv *tx_info_priv;
 	struct ath_atx_tid *tid = NULL;
 	struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
 	struct ath_desc *ds = bf_last->bf_desc;
@@ -280,9 +283,13 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
 	skb = bf->bf_mpdu;
 	hdr = (struct ieee80211_hdr *)skb->data;
 
+	tx_info = IEEE80211_SKB_CB(skb);
+	tx_info_priv = (struct ath_tx_info_priv *) tx_info->rate_driver_data[0];
+	hw = tx_info_priv->aphy->hw;
+
 	rcu_read_lock();
 
-	sta = ieee80211_find_sta(sc->hw, hdr->addr1);
+	sta = ieee80211_find_sta(hw, hdr->addr1);
 	if (!sta) {
 		rcu_read_unlock();
 		return;
-- 
1.6.5.2.143.g8cc62


^ permalink raw reply related

* [RFT 3/9] ath9k: simpify RX by calling ath_get_virt_hw() once
From: Luis R. Rodriguez @ 2009-11-03  3:07 UTC (permalink / raw)
  To: linux-wireless; +Cc: ath9k-devel, Luis R. Rodriguez, Jouni.Malinen
In-Reply-To: <1257217681-27180-1-git-send-email-lrodriguez@atheros.com>

ath_get_virt_hw() is required on RX to determine for which virtual
wiphy an skb came in for. Instead of searching for the hw twice do
it only once.

Cc: Jouni.Malinen <Jouni.Malinen@atheros.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/recv.c |   28 ++++++++++++++++++----------
 1 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index c880a55..330cd3b 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -105,23 +105,21 @@ static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
  * up the frame up to let mac80211 handle the actual error case, be it no
  * decryption key or real decryption error. This let us keep statistics there.
  */
-static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
+static int ath_rx_prepare(struct ieee80211_hw *hw,
+			  struct sk_buff *skb, struct ath_desc *ds,
 			  struct ieee80211_rx_status *rx_status, bool *decrypt_error,
 			  struct ath_softc *sc)
 {
 	struct ieee80211_hdr *hdr;
 	u8 ratecode;
 	__le16 fc;
-	struct ieee80211_hw *hw;
 	struct ieee80211_sta *sta;
 	struct ath_node *an;
 	int last_rssi = ATH_RSSI_DUMMY_MARKER;
 
-
 	hdr = (struct ieee80211_hdr *)skb->data;
 	fc = hdr->frame_control;
 	memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
-	hw = ath_get_virt_hw(sc, hdr);
 
 	if (ds->ds_rxstat.rs_more) {
 		/*
@@ -615,7 +613,8 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
 	}
 }
 
-static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
+static void ath_rx_send_to_mac80211(struct ieee80211_hw *hw,
+				    struct ath_softc *sc, struct sk_buff *skb,
 				    struct ieee80211_rx_status *rx_status)
 {
 	struct ieee80211_hdr *hdr;
@@ -647,7 +646,7 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
 	} else {
 		/* Deliver unicast frames based on receiver address */
 		memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
-		ieee80211_rx(ath_get_virt_hw(sc, hdr), skb);
+		ieee80211_rx(hw, skb);
 	}
 }
 
@@ -663,6 +662,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 	struct ieee80211_rx_status rx_status;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
+	/*
+	 * The hw can techncically differ from common->hw when using ath9k
+	 * virtual wiphy so to account for that we iterate over the active
+	 * wiphys and find the appropriate wiphy and therefore hw.
+	 */
+	struct ieee80211_hw *hw = NULL;
 	struct ieee80211_hdr *hdr;
 	int hdrlen, padsize, retval;
 	bool decrypt_error = false;
@@ -742,6 +747,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 				sc->rx.bufsize,
 				DMA_FROM_DEVICE);
 
+		hdr = (struct ieee80211_hdr *) skb->data;
+		hw = ath_get_virt_hw(sc, hdr);
+
 		/*
 		 * If we're asked to flush receive queue, directly
 		 * chain it back at the queue without processing it.
@@ -756,7 +764,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 		if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen)
 			goto requeue;
 
-		if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc))
+		if (!ath_rx_prepare(hw, skb, ds,
+				    &rx_status, &decrypt_error, sc))
 			goto requeue;
 
 		/* Ensure we always have an skb to requeue once we are done
@@ -778,7 +787,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 		skb_put(skb, ds->ds_rxstat.rs_datalen);
 
 		/* see if any padding is done by the hw and remove it */
-		hdr = (struct ieee80211_hdr *)skb->data;
 		hdrlen = ieee80211_get_hdrlen_from_skb(skb);
 		fc = hdr->frame_control;
 
@@ -825,7 +833,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 			bf->bf_mpdu = NULL;
 			ath_print(common, ATH_DBG_FATAL,
 				  "dma_mapping_error() on RX\n");
-			ath_rx_send_to_mac80211(sc, skb, &rx_status);
+			ath_rx_send_to_mac80211(hw, sc, skb, &rx_status);
 			break;
 		}
 		bf->bf_dmacontext = bf->bf_buf_addr;
@@ -846,7 +854,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 					     SC_OP_WAIT_FOR_PSPOLL_DATA)))
 			ath_rx_ps(sc, skb);
 
-		ath_rx_send_to_mac80211(sc, skb, &rx_status);
+		ath_rx_send_to_mac80211(hw, sc, skb, &rx_status);
 
 requeue:
 		list_move_tail(&bf->list, &sc->rx.rxbuf);
-- 
1.6.5.2.143.g8cc62


^ permalink raw reply related

* [RFT 5/9] ath9k: pass the ieee80211_hw on radio enable/disable
From: Luis R. Rodriguez @ 2009-11-03  3:07 UTC (permalink / raw)
  To: linux-wireless; +Cc: ath9k-devel, Luis R. Rodriguez, Jouni.Malinen
In-Reply-To: <1257217681-27180-1-git-send-email-lrodriguez@atheros.com>

We use the ieee80211_hw for radio enable/disable but the wrong
structure hw was being used in consideration for virtual wiphys
as each virtual wiphy has its own ieee80211_hw struct.

Just pass the hw struct to ensure we use the right one. This should
fix the hw used and passed for radio enable/disable. This includes
the stoping / starting of the software TX queues so mac80211 doesn't
send us data for a specific virtual wiphy. ath9k already takes care
of pausing virtual wiphys and stopping the respective queues on its
own, but this should handle the idle mac80211 conf calls as well.

Cc: Jouni.Malinen <Jouni.Malinen@atheros.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/ath9k.h   |    5 +++--
 drivers/net/wireless/ath/ath9k/main.c    |   18 +++++++++---------
 drivers/net/wireless/ath/ath9k/virtual.c |    5 +++--
 3 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index da53578..59ce7ec 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -655,8 +655,9 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
 void ath_update_chainmask(struct ath_softc *sc, int is_ht);
 int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
 		    struct ath9k_channel *hchan);
-void ath_radio_enable(struct ath_softc *sc);
-void ath_radio_disable(struct ath_softc *sc);
+
+void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw);
+void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
 
 #ifdef CONFIG_PCI
 int ath_pci_init(void);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index bdce0ab..11aaa7d 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1200,11 +1200,11 @@ fail:
 	ath_deinit_leds(sc);
 }
 
-void ath_radio_enable(struct ath_softc *sc)
+void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 {
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
-	struct ieee80211_channel *channel = sc->hw->conf.channel;
+	struct ieee80211_channel *channel = hw->conf.channel;
 	int r;
 
 	ath9k_ps_wakeup(sc);
@@ -1241,18 +1241,18 @@ void ath_radio_enable(struct ath_softc *sc)
 			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 	ath9k_hw_set_gpio(ah, ah->led_pin, 0);
 
-	ieee80211_wake_queues(sc->hw);
+	ieee80211_wake_queues(hw);
 	ath9k_ps_restore(sc);
 }
 
-void ath_radio_disable(struct ath_softc *sc)
+void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw)
 {
 	struct ath_hw *ah = sc->sc_ah;
-	struct ieee80211_channel *channel = sc->hw->conf.channel;
+	struct ieee80211_channel *channel = hw->conf.channel;
 	int r;
 
 	ath9k_ps_wakeup(sc);
-	ieee80211_stop_queues(sc->hw);
+	ieee80211_stop_queues(hw);
 
 	/* Disable LED */
 	ath9k_hw_set_gpio(ah, ah->led_pin, 1);
@@ -1266,7 +1266,7 @@ void ath_radio_disable(struct ath_softc *sc)
 	ath_flushrecv(sc);		/* flush recv queue */
 
 	if (!ah->curchan)
-		ah->curchan = ath_get_curchannel(sc, sc->hw);
+		ah->curchan = ath_get_curchannel(sc, hw);
 
 	spin_lock_bh(&sc->sc_resetlock);
 	r = ath9k_hw_reset(ah, ah->curchan, false);
@@ -2719,7 +2719,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 		spin_unlock_bh(&sc->wiphy_lock);
 
 		if (enable_radio) {
-			ath_radio_enable(sc);
+			ath_radio_enable(sc, hw);
 			ath_print(common, ATH_DBG_CONFIG,
 				  "not-idle: enabling radio\n");
 		}
@@ -2800,7 +2800,7 @@ skip_chan_change:
 
 	if (disable_radio) {
 		ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
-		ath_radio_disable(sc);
+		ath_radio_disable(sc, hw);
 	}
 
 	mutex_unlock(&sc->mutex);
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index 7678c4a..69a871b 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -526,8 +526,9 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy)
 			 * frame being completed)
 			 */
 			spin_unlock_bh(&sc->wiphy_lock);
-			ath_radio_disable(sc);
-			ath_radio_enable(sc);
+			ath_radio_disable(sc, aphy->hw);
+			ath_radio_enable(sc, aphy->hw);
+			/* Only the primary wiphy hw is used for queuing work */
 			ieee80211_queue_work(aphy->sc->hw,
 				   &aphy->sc->chan_work);
 			return -EBUSY; /* previous select still in progress */
-- 
1.6.5.2.143.g8cc62


^ permalink raw reply related

* [RFT 1/9] ath9k: fix listening to idle requests
From: Luis R. Rodriguez @ 2009-11-03  3:07 UTC (permalink / raw)
  To: linux-wireless; +Cc: ath9k-devel, Luis R. Rodriguez, Jouni.Malinen
In-Reply-To: <1257217681-27180-1-git-send-email-lrodriguez@atheros.com>

The way idle configuration detection was implemented as
busted due to the fact that it assumed the ath9k virtual wiphy,
the aphy, would be marked as inactive if it was not used but
it turns out an aphy is always active if its the only wiphy
present. We need to distinguish between aphy activity and
idleness so we now add an idle bool for the aphy and mark
it as such based on the passed IEEE80211_CONF_CHANGE_IDLE
from mac80211.

Previous to all_wiphys_idle would never be true when using
only one device so we never really were using
IEEE80211_CONF_CHANGE_IDLE -- we never turned the radio
off or on upon IEEE80211_CONF_CHANGE_IDLE changes as radio
changes depended on all_wiphys_idle being true either to
turn the radio on or off. Since it was always false for
one device this code was doing nothing.

Cc: Jouni.Malinen <Jouni.Malinen@atheros.com>
Reported-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/ath9k.h   |    2 +
 drivers/net/wireless/ath/ath9k/main.c    |   33 +++++++++++++++++++++++------
 drivers/net/wireless/ath/ath9k/virtual.c |   17 ++++++++++++--
 3 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 13dd020..da53578 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -620,6 +620,7 @@ struct ath_wiphy {
 		ATH_WIPHY_PAUSED,
 		ATH_WIPHY_SCAN,
 	} state;
+	bool idle;
 	int chan_idx;
 	int chan_is_ht;
 };
@@ -691,6 +692,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
 bool ath9k_wiphy_scanning(struct ath_softc *sc);
 void ath9k_wiphy_work(struct work_struct *work);
 bool ath9k_all_wiphys_idle(struct ath_softc *sc);
+void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle);
 
 int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype);
 #endif /* ATH9K_H */
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 9fefc51..bdce0ab 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2688,22 +2688,37 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 	struct ath_common *common = ath9k_hw_common(sc->sc_ah);
 	struct ieee80211_conf *conf = &hw->conf;
 	struct ath_hw *ah = sc->sc_ah;
-	bool all_wiphys_idle = false, disable_radio = false;
+	bool disable_radio;
 
 	mutex_lock(&sc->mutex);
 
-	/* Leave this as the first check */
+	/*
+	 * Leave this as the first check because we need to turn on the
+	 * radio if it was disabled before prior to processing the rest
+	 * of the changes. Likewise we must only disable the radio towards
+	 * the end.
+	 */
 	if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+		bool enable_radio;
+		bool all_wiphys_idle;
+		bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
 
 		spin_lock_bh(&sc->wiphy_lock);
 		all_wiphys_idle =  ath9k_all_wiphys_idle(sc);
+		ath9k_set_wiphy_idle(aphy, idle);
+
+		if (!idle && all_wiphys_idle)
+			enable_radio = true;
+
+		/*
+		 * After we unlock here its possible another wiphy
+		 * can be re-renabled so to account for that we will
+		 * only disable the radio toward the end of this routine
+		 * if by then all wiphys are still idle.
+		 */
 		spin_unlock_bh(&sc->wiphy_lock);
 
-		if (conf->flags & IEEE80211_CONF_IDLE){
-			if (all_wiphys_idle)
-				disable_radio = true;
-		}
-		else if (all_wiphys_idle) {
+		if (enable_radio) {
 			ath_radio_enable(sc);
 			ath_print(common, ATH_DBG_CONFIG,
 				  "not-idle: enabling radio\n");
@@ -2779,6 +2794,10 @@ skip_chan_change:
 	if (changed & IEEE80211_CONF_CHANGE_POWER)
 		sc->config.txpowlimit = 2 * conf->power_level;
 
+	spin_lock_bh(&sc->wiphy_lock);
+	disable_radio = ath9k_all_wiphys_idle(sc);
+	spin_unlock_bh(&sc->wiphy_lock);
+
 	if (disable_radio) {
 		ath_print(common, ATH_DBG_CONFIG, "idle: disabling radio\n");
 		ath_radio_disable(sc);
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index bc7d173..e6a50f3 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -668,15 +668,26 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
 bool ath9k_all_wiphys_idle(struct ath_softc *sc)
 {
 	unsigned int i;
-	if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) {
+	if (!sc->pri_wiphy->idle)
 		return false;
-	}
 	for (i = 0; i < sc->num_sec_wiphy; i++) {
 		struct ath_wiphy *aphy = sc->sec_wiphy[i];
 		if (!aphy)
 			continue;
-		if (aphy->state != ATH_WIPHY_INACTIVE)
+		if (!aphy->idle)
 			return false;
 	}
 	return true;
 }
+
+/* caller must hold wiphy_lock */
+void ath9k_set_wiphy_idle(struct ath_wiphy *aphy, bool idle)
+{
+	struct ath_softc *sc = aphy->sc;
+
+	aphy->idle = idle;
+	ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
+		  "Marking %s as %s\n",
+		  wiphy_name(aphy->hw->wiphy),
+		  idle ? "idle" : "not-idle");
+}
-- 
1.6.5.2.143.g8cc62


^ permalink raw reply related

* [RFT 0/9] ath9k: few updates for virtual wiphy
From: Luis R. Rodriguez @ 2009-11-03  3:07 UTC (permalink / raw)
  To: linux-wireless; +Cc: ath9k-devel, Luis R. Rodriguez

Here are a few fixes for the ath9k virtual wiphy. I thought I was
going to have time to test them all today but that didn't happen
so instead of letting them rot in my queue for a few days I'm
posting them for review.

I was not able to find an easy way to deal with the ah->opmode,
that should be updated based on the currently used ieee80211_vif
but mac80211 doesn't exactly tell us which vif we're using at any
given time -- instead each driver is supposed to support different
modes of operation on different vifs on one wiphy. With ath9k
virtual wiphy we've taken a different approach: two vifs can
have different operating modes but on at least they get to use
their own separate channel.

While we can reap benefits of using a separate channel with the
current implementation there are a few cases where mac80211 makes
it difficult to guess your current hw configuration, mainly because
it wasn't designed for two vifs on separate wiphys on the same hardware.

We'd still need to figure out a way to deal with the ah->opmode but
that varies depending on the used vif, and the rx filter also changes
depending on the vif we're on but we have no way of triggering an
appropriate filter update unless mac80211 does it by chance for us.

Luis R. Rodriguez (9):
  ath9k: fix listening to idle requests
  ath9k: update hw configuration for virtual wiphys
  ath9k: simpify RX by calling ath_get_virt_hw() once
  ath9k: use the passed ieee80211_hw on ath_rx_prepare()
  ath9k: pass the ieee80211_hw on radio enable/disable
  ath9k: use correct hw for tx aggregation TX completion
  ath9k: use the right hw on ath_tx_setup_buffer() for HT
  ath9k: handle low buffer space for virtual wiphys
  ath9k: do not pass the entire descriptor to ath_rx_prepare()

 drivers/net/wireless/ath/ath9k/ath9k.h   |   10 +++-
 drivers/net/wireless/ath/ath9k/main.c    |   51 +++++++++++-----
 drivers/net/wireless/ath/ath9k/recv.c    |   96 ++++++++++++++++-------------
 drivers/net/wireless/ath/ath9k/virtual.c |   79 +++++++++++++++++++++++--
 drivers/net/wireless/ath/ath9k/xmit.c    |   21 ++++--
 5 files changed, 184 insertions(+), 73 deletions(-)


^ permalink raw reply

* RE: [ipw3945-devel] iwl3945 microcode errors
From: Cahill, Ben M @ 2009-11-03  2:07 UTC (permalink / raw)
  To: Maxim Levitsky, iwlwifi maling list, linux-wireless
In-Reply-To: <1257208794.6556.2.camel@maxim-laptop>

Thanks for the report; disappointing news.

Don't forget to load driver with debug=0x43fff, to get Error and Event logs.

-- Ben -- 

>-----Original Message-----
>From: Maxim Levitsky [mailto:maximlevitsky@gmail.com] 
>Sent: Monday, November 02, 2009 7:40 PM
>To: iwlwifi maling list; linux-wireless
>Subject: [ipw3945-devel] iwl3945 microcode errors
>
>I see that iwl3945 began to show some microcode errors like that:
>
>[   18.259947] iwl3945 0000:06:00.0: firmware: requesting 
>iwlwifi-3945-2.ucode
>[   18.766225] iwl3945 0000:06:00.0: loaded firmware version 15.32.2.9
>[   18.817952] iwl3945 0000:06:00.0: Microcode SW error 
>detected. Restarting 0x82000008.
>[   18.817971] iwl3945 0000:06:00.0: Error Reply type 
>0x00000000 cmd UNKNOWN (0x88) seq 0xDB3B ser 0x00880000
>[   18.822468] iwl3945 0000:06:00.0: Can't stop Rx DMA.
>[   20.790058] iwl3945 0000:06:00.0: Wait for START_ALIVE 
>timeout after 2000ms.
>
>Now it still works, but there were cases it didn't.
>
>I post more detailed info soon.
>
>Best regards,
>	Maxim Levitsky
>
>
>---------------------------------------------------------------
>---------------
>Come build with us! The BlackBerry(R) Developer Conference in SF, CA
>is the only developer event you need to attend this year. 
>Jumpstart your
>developing skills, take BlackBerry mobile applications to 
>market and stay 
>ahead of the curve. Join us from November 9 - 12, 2009. Register now!
>http://p.sf.net/sfu/devconference
>_______________________________________________
>Ipw3945-devel mailing list
>Ipw3945-devel@lists.sourceforge.net
>https://lists.sourceforge.net/lists/listinfo/ipw3945-devel
>

^ permalink raw reply

* Re: [PATCH] ar9170usb: add mode-switching for AVM Fritz!WLAN USB N devices in cdrom mode
From: Dan Williams @ 2009-11-03  0:54 UTC (permalink / raw)
  To: Alan Cox; +Cc: Matthew Dharm, Frank Schaefer, linux-wireless, linux-usb
In-Reply-To: <20091102223903.4378e0fa@lxorguk.ukuu.org.uk>

On Mon, 2009-11-02 at 22:39 +0000, Alan Cox wrote:
> > Maybe we can get the kernel drivers to expose the information we need
> > (maybe even an 'eject' attribute in sysfs or something) and then we just
> > have to write udev rules instead of having a whole bunch of libusb junk
> > in userspace?  Would that preserve the policy-always-in-userspace
> > requirement yet keep the code to drive the hardware in kernel space
> > where it really belongs?
> 
> Or put the magic strings in the kernel with a translation hook for the
> eject request ? That would keep policy and method in the right places.
> You ask the kernel to eject, it hides the magic weirdness.

Yes, that would be awesome.

Dan


^ permalink raw reply

* Re: Incorrect signal levels reported using wpa_supplicant's driver_nl80211
From: Dan Williams @ 2009-11-03  0:53 UTC (permalink / raw)
  To: Maxim Levitsky
  Cc: hostap@lists.shmoo.com, linux-wireless, networkmanager-list
In-Reply-To: <1257203242.6717.14.camel@maxim-laptop>

On Tue, 2009-11-03 at 01:07 +0200, Maxim Levitsky wrote:
> On Mon, 2009-11-02 at 11:40 -0800, Dan Williams wrote: 
> > On Sat, 2009-10-31 at 03:50 +0200, Maxim Levitsky wrote:
> > > Sorry for cross-posting, but this issue really spans all three systems.
> > > 
> > > I anylized why I get 100% quality on all access points except currently
> > > connected, when I used driver_nl80211 of wpa_supplcant.
> > > 
> > > First, when NetworkManager plans to switch to this driver?
> > 
> > Soon.  We've got some patches for this, but we'll also need tons of
> > testing.  The WEXT stuff is pretty baked while nl80211 is still under
> > some flux.  But of course the only way we bake nl80211 is by switching
> > to it...
> Glad to hear that!
> 
> I use driver_nl80211 and I have 3 problems.
> 
> 1 - noise levels, this what I reported here.
> 2 - problems with wpa_supplicant that does no deauth on disconnect,
> this can be easily worked around in supplicant code, but I feel some
> disagreement between kernel and wpa_supplicant developers.
> 
> 3 - seems that ibss is broken (even with all recently posted patches on
> linux-wireless, wpa_supplicant still hangs while it attempts to create
> the network. In fact I only tested creation of the network, not if
> anybody could join it.
> 
> 
> Speaking of joing the IBSS, NM did forever support the WPA encryption,
> however, its isn't set in the beacon that is broadcast (in fact I only
> see probe requests, not real beacons...)
> Thus any attempt to join such network results in NM asking for wep keys.

That's a mac80211/supplicant problem, I believe.  NM just sends the
config to the supplicant, and given that config, it's the supplicant and
driver's problem to set up the right network.  You can see the config
that NM sends in /var/log/messages or /var/log/daemon.log, wherever your
distro directs the 'daemon' syslog facility.

Dan

> It would be very nice to have WPA/2 IBSS, as this is the only real
> encryption possible.
> 
> 
> > 
> > > For me it gives me faster association speeds, especially when I toggle
> > > wireless with rfkill button.
> > > 
> > > 
> > > this is what happens on the kernel side:
> > > --> n80211 encodes only dBm data. It does so in, nl80211_send_bss.
> > > 	(or it can encode unspecified data, which has little use...)
> > > 
> > > --> kernel also gives maximum ranges in, cfg80211_wext_giwrange, which is used by NM:
> > > 	range->max_qual.updated = IW_QUAL_NOISE_INVALID | IW_QUAL_DBM | IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED ;
> > > 	range->max_qual.level = -110;
> > > 	range->max_qual.qual = 70;
> > > Thus it reports that it can't report noise.
> > > 
> > > 
> > > driver_nl80211 side:
> > > 
> > > --> sends data as is, done in bss_info_handler:
> > > 	r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
> > > 	r->level /= 100; /* mBm to dBm */
> > > 	r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
> > > 
> > > Again explicitly says that has no quality data, sends only dBm or unspecified data;
> > > 
> > > 
> > > 
> > > NM side:
> > > 
> > > --> three strategies used (in wireless_qual_to_percent)
> > > 	--> quality: (used with driver_wext), not reported by nl80211
> > > 
> > > 	--> dbm: used only if:
> > > 		* valid and zero max_qual->level (but now set to -110....) 
> > 
> > IIRC non-zero max_qual->level was the indication that the driver wanted
> > to use RSSI, not dBm.  Since the real "max" dBm is around 0 (ie, that's
> > the highest signal strength you'll ever really see), max_qual->level
> > meant the driver was reporting signal strength in dBm.  max_qual->level
> > == -110 is kinda wrong, because that's the _minimum_ level, not the max.
> This is very good point, a question for kernel developers, why it was
> set as such? How about setting it to ?
> 
> 
> > The noise floor is almost always around -100 dBm so setting
> > max_qual->level is pretty useless.
> > 
> > This is *exactly* why 'qual' is there: so that the driver itself can
> > figure out what the hell it's signal level is, and so that NM doesn't
> > have to go around assuming stuff.
> It appears as kernel developers want to drop quality calculations
> altogether, and report everything in dBms (right?) 
> This is also a consistent I think.
> 
> > 
> > For WEXT reporting, mac80211 should really be constructing a 'qual'
> > instead of leaving it 0.  Then we don't have ambiguities with dBm, RSSI,
> > unspec, etc.
> It does, but driver_nl80211 doesn't use wext that is.
> 
> 
> Also a recent conversation on linux-wireless indicated that noise level
> is a property of the wireless card, so I think we won't see them in scan
> results any time soon.
> 
> 
> Best regards,
> Maxim Levitsky
> 


^ permalink raw reply

* iwl3945 microcode errors
From: Maxim Levitsky @ 2009-11-03  0:39 UTC (permalink / raw)
  To: iwlwifi maling list, linux-wireless

I see that iwl3945 began to show some microcode errors like that:

[   18.259947] iwl3945 0000:06:00.0: firmware: requesting iwlwifi-3945-2.ucode
[   18.766225] iwl3945 0000:06:00.0: loaded firmware version 15.32.2.9
[   18.817952] iwl3945 0000:06:00.0: Microcode SW error detected. Restarting 0x82000008.
[   18.817971] iwl3945 0000:06:00.0: Error Reply type 0x00000000 cmd UNKNOWN (0x88) seq 0xDB3B ser 0x00880000
[   18.822468] iwl3945 0000:06:00.0: Can't stop Rx DMA.
[   20.790058] iwl3945 0000:06:00.0: Wait for START_ALIVE timeout after 2000ms.

Now it still works, but there were cases it didn't.

I post more detailed info soon.

Best regards,
	Maxim Levitsky


^ permalink raw reply

* ath5k and ".local" dropout
From: CSights @ 2009-11-03  0:07 UTC (permalink / raw)
  To: linux-wireless

Hello,
	I'm having a problem with the ath5k module found in kernel 2.6.31.5 and 
accessing ".local" addresses on the network.
	What I've observed so far is that when I first boot the computer I can 
successfully access (e.g. ping) other .local computers.  If the computer with 
the ath5k card sits for a few minutes I can no longer access .local 
computers.  (Trying to ping, ping returns "ping: unknown host")  Also, other 
computers on the network can no longer ping the ath5k computer (also "ping: 
unknown host")
	Pinging the .local computers by their IP address (e.g. 192.168.1.3) does 
work.
	Access to computers "on the internet" (e.g. www.case.edu) also works.

	At first I thought this was a problem with Avahi.  Later I tried a different 
wireless card (one that uses the RT2500pci module) and there was no problem 
with the .local fading away after a few minutes.

02:04.0 Ethernet controller: Atheros Communications Inc. AR5212/AR5213 
Multiprotocol MAC/baseband processor (rev 01)                                            
        Subsystem: Compaq Computer Corporation Device 00e5                      
        Flags: medium devsel, IRQ 11                                            
        Memory at 90080000 (32-bit, non-prefetchable) [size=64K]                
        Capabilities: [44] Power Management version 2                           
        Kernel modules: ath5k

Anything else to try?  (I'm not subscribed to mailing list, so CC me in 
responses please!)

Thanks for your work!
	C.

^ permalink raw reply

* Re: 2.6.32-rc5-git3: Reported regressions from 2.6.31
From: Christian Casteyde @ 2009-11-02 23:43 UTC (permalink / raw)
  To: Michael Buesch; +Cc: John W. Linville, linux-wireless, Johannes Berg
In-Reply-To: <200911011628.34535.mb@bu3sch.de>

Nothing to mention: it seems to work, at least on my hardware.
I got the Allocated bounce buffer log, and managed to boot without any error, 
associate and access the web/ssh another computer (and didn't get any 
kmemcheck error of course).

CC

Le dimanche 01 novembre 2009 16:28:34, Michael Buesch a écrit :
> On Wednesday 28 October 2009 21:38:37 Christian Casteyde wrote:
> > I've just tested the patch posted in bugzilla: it works.
> > That is, I do not manage to get the warning anymore in 3 boots in a row.
> 
> Can you try this patch (on top of the previous one), please?
> It should fix the issue correctly by removing the skb copying.
> While testing make sure the debugging message
> "Allocated bounce buffer"
> shows up in the kernel log.
> 
> 
> 
> Index: wireless-testing/drivers/net/wireless/b43/dma.c
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/b43/dma.c	2009-11-01
>  15:10:48.000000000 +0100 +++
>  wireless-testing/drivers/net/wireless/b43/dma.c	2009-11-01
>  16:26:00.000000000 +0100 @@ -1157,18 +1157,17 @@ struct b43_dmaring
>  *parse_cookie(struct
>  }
> 
>  static int dma_tx_fragment(struct b43_dmaring *ring,
> -			   struct sk_buff **in_skb)
> +			   struct sk_buff *skb)
>  {
> -	struct sk_buff *skb = *in_skb;
>  	const struct b43_dma_ops *ops = ring->ops;
>  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
> +	struct b43_private_tx_info *priv_info = b43_get_priv_tx_info(info);
>  	u8 *header;
>  	int slot, old_top_slot, old_used_slots;
>  	int err;
>  	struct b43_dmadesc_generic *desc;
>  	struct b43_dmadesc_meta *meta;
>  	struct b43_dmadesc_meta *meta_hdr;
> -	struct sk_buff *bounce_skb;
>  	u16 cookie;
>  	size_t hdrsize = b43_txhdr_size(ring->dev);
> 
> @@ -1212,34 +1211,34 @@ static int dma_tx_fragment(struct b43_dm
> 
>  	meta->skb = skb;
>  	meta->is_last_fragment = 1;
> +	priv_info->bouncebuffer = NULL;
> 
>  	meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
>  	/* create a bounce buffer in zone_dma on mapping failure. */
>  	if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
> -		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
> -		if (!bounce_skb) {
> +
> +{
> +static unsigned int count;
> +if (count++ < 10)
> +	printk(KERN_DEBUG "Allocated bounce buffer\n");
> +}
> +		priv_info->bouncebuffer = kmalloc(skb->len, GFP_ATOMIC | GFP_DMA);
> +		if (!priv_info->bouncebuffer) {
>  			ring->current_slot = old_top_slot;
>  			ring->used_slots = old_used_slots;
>  			err = -ENOMEM;
>  			goto out_unmap_hdr;
>  		}
> +		memcpy(priv_info->bouncebuffer, skb->data, skb->len);
> 
> -		memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
> -		memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb));
> -		bounce_skb->dev = skb->dev;
> -		skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb));
> -		info = IEEE80211_SKB_CB(bounce_skb);
> -
> -		dev_kfree_skb_any(skb);
> -		skb = bounce_skb;
> -		*in_skb = bounce_skb;
> -		meta->skb = skb;
> -		meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
> +		meta->dmaaddr = map_descbuffer(ring, priv_info->bouncebuffer, skb->len,
>  1); if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
> +			kfree(priv_info->bouncebuffer);
> +			priv_info->bouncebuffer = NULL;
>  			ring->current_slot = old_top_slot;
>  			ring->used_slots = old_used_slots;
>  			err = -EIO;
> -			goto out_free_bounce;
> +			goto out_unmap_hdr;
>  		}
>  	}
> 
> @@ -1256,8 +1255,6 @@ static int dma_tx_fragment(struct b43_dm
>  	ops->poke_tx(ring, next_slot(ring, slot));
>  	return 0;
> 
> -out_free_bounce:
> -	dev_kfree_skb_any(skb);
>  out_unmap_hdr:
>  	unmap_descbuffer(ring, meta_hdr->dmaaddr,
>  			 hdrsize, 1);
> @@ -1362,11 +1359,7 @@ int b43_dma_tx(struct b43_wldev *dev, st
>  	 * static, so we don't need to store it per frame. */
>  	ring->queue_prio = skb_get_queue_mapping(skb);
> 
> -	/* dma_tx_fragment might reallocate the skb, so invalidate pointers
>  pointing -	 * into the skb data or cb now. */
> -	hdr = NULL;
> -	info = NULL;
> -	err = dma_tx_fragment(ring, &skb);
> +	err = dma_tx_fragment(ring, skb);
>  	if (unlikely(err == -ENOKEY)) {
>  		/* Drop this packet, as we don't have the encryption key
>  		 * anymore and must not transmit it unencrypted. */
> @@ -1413,12 +1406,17 @@ void b43_dma_handle_txstatus(struct b43_
>  		B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
>  		desc = ops->idx2desc(ring, slot, &meta);
> 
> -		if (meta->skb)
> -			unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len,
> -					 1);
> -		else
> +		if (meta->skb) {
> +			struct b43_private_tx_info *priv_info =
> +				b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
> +
> +			unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
> +			kfree(priv_info->bouncebuffer);
> +			priv_info->bouncebuffer = NULL;
> +		} else {
>  			unmap_descbuffer(ring, meta->dmaaddr,
>  					 b43_txhdr_size(dev), 1);
> +		}
> 
>  		if (meta->is_last_fragment) {
>  			struct ieee80211_tx_info *info;
> Index: wireless-testing/drivers/net/wireless/b43/xmit.h
> ===================================================================
> --- wireless-testing.orig/drivers/net/wireless/b43/xmit.h	2009-10-09
>  19:50:15.000000000 +0200 +++
>  wireless-testing/drivers/net/wireless/b43/xmit.h	2009-11-01
>  16:05:46.000000000 +0100 @@ -2,6 +2,8 @@
>  #define B43_XMIT_H_
> 
>  #include "main.h"
> +#include <net/mac80211.h>
> +
> 
>  #define _b43_declare_plcp_hdr(size) \
>  	struct b43_plcp_hdr##size {		\
> @@ -332,4 +334,21 @@ static inline u8 b43_kidx_to_raw(struct
>  	return raw_kidx;
>  }
> 
> +/* struct b43_private_tx_info - TX info private to b43.
> + * The structure is placed in (struct ieee80211_tx_info
>  *)->rate_driver_data + *
> + * @bouncebuffer: DMA Bouncebuffer (if used)
> + */
> +struct b43_private_tx_info {
> +	void *bouncebuffer;
> +};
> +
> +static inline struct b43_private_tx_info *
> +b43_get_priv_tx_info(struct ieee80211_tx_info *info)
> +{
> +	BUILD_BUG_ON(sizeof(struct b43_private_tx_info) >
> +		     sizeof(info->rate_driver_data));
> +	return (struct b43_private_tx_info *)info->rate_driver_data;
> +}
> +
>  #endif /* B43_XMIT_H_ */
> 

^ permalink raw reply

* Re: [PATCH 1/2] Allow scanning while in authenticated only state
From: Maxim Levitsky @ 2009-11-02 23:17 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: Johannes Berg, hostap@lists.shmoo.com, linux-wireless
In-Reply-To: <20091101201024.GA29524@jm.kir.nu>

On Sun, 2009-11-01 at 22:10 +0200, Jouni Malinen wrote: 
> On Sat, Oct 31, 2009 at 12:33:16PM +0200, Maxim Levitsky wrote:
> 
> > How about putting this in wpa_supplicant, and end all trouble with this
> > for once?
> > 
> > This is a workaround/hack, but at least it works....
> 
> Could you please add a comment pointing that out and explaining that the
> deauth in disassoc is there due to mac80211's inability to handle
> multiple APs in authenticated-but-not-associated state?
I resend this patch with proper comment.

> 
> > diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
> >  static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
> >                                            int reason_code)
> 
> > -       return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE,
> > +
> > +       err = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE,
> > +                                      reason_code);
> > +       if (err)
> > +               return err;
> > +       return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
> >                                        reason_code);
> 
> There should be no need for doing both disassoc and deauth; just send
> deauth only if that is needed. This will save one extra frame
> transmission and speeds up roaming a bit.
> 
> Though, is this enough to handle the roaming cases where wpa_supplicant
> may not try to send either disassociation or deauthentication?
Currently wpa_supplicant sends only disassociation.
deauthentication is send only in rare cases, usually due to [suspected]
authentication error.
Other that that I don't know, what I need is a clear statement about how
things should work that is:


* Should kernel allow authentication while in authenticated? I guess yes
To same AP? To different APs?

* What should kernel do if it done authentication to several APs?, but
not association.
should it timeout, or let wpa_suplicant do it?
Currently it allows 4 (or 3) such APs, and then then bugs out with
-ENOSPC


* Should kernel allow scanning while in authenticated but not associated
case? 
I have send patch to do so, I hope it will be accepted.


While 3 (or more if I didn't find all of them) problems remain, this
workaround is the only solution.


Best regards,
Maxim Levitsky


^ permalink raw reply

* Re: Incorrect signal levels reported using wpa_supplicant's driver_nl80211
From: Maxim Levitsky @ 2009-11-02 23:07 UTC (permalink / raw)
  To: Dan Williams; +Cc: hostap@lists.shmoo.com, linux-wireless, networkmanager-list
In-Reply-To: <1257190833.1027.4.camel@localhost.localdomain>

On Mon, 2009-11-02 at 11:40 -0800, Dan Williams wrote: 
> On Sat, 2009-10-31 at 03:50 +0200, Maxim Levitsky wrote:
> > Sorry for cross-posting, but this issue really spans all three systems.
> > 
> > I anylized why I get 100% quality on all access points except currently
> > connected, when I used driver_nl80211 of wpa_supplcant.
> > 
> > First, when NetworkManager plans to switch to this driver?
> 
> Soon.  We've got some patches for this, but we'll also need tons of
> testing.  The WEXT stuff is pretty baked while nl80211 is still under
> some flux.  But of course the only way we bake nl80211 is by switching
> to it...
Glad to hear that!

I use driver_nl80211 and I have 3 problems.

1 - noise levels, this what I reported here.
2 - problems with wpa_supplicant that does no deauth on disconnect,
this can be easily worked around in supplicant code, but I feel some
disagreement between kernel and wpa_supplicant developers.

3 - seems that ibss is broken (even with all recently posted patches on
linux-wireless, wpa_supplicant still hangs while it attempts to create
the network. In fact I only tested creation of the network, not if
anybody could join it.


Speaking of joing the IBSS, NM did forever support the WPA encryption,
however, its isn't set in the beacon that is broadcast (in fact I only
see probe requests, not real beacons...)
Thus any attempt to join such network results in NM asking for wep keys.

It would be very nice to have WPA/2 IBSS, as this is the only real
encryption possible.


> 
> > For me it gives me faster association speeds, especially when I toggle
> > wireless with rfkill button.
> > 
> > 
> > this is what happens on the kernel side:
> > --> n80211 encodes only dBm data. It does so in, nl80211_send_bss.
> > 	(or it can encode unspecified data, which has little use...)
> > 
> > --> kernel also gives maximum ranges in, cfg80211_wext_giwrange, which is used by NM:
> > 	range->max_qual.updated = IW_QUAL_NOISE_INVALID | IW_QUAL_DBM | IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED ;
> > 	range->max_qual.level = -110;
> > 	range->max_qual.qual = 70;
> > Thus it reports that it can't report noise.
> > 
> > 
> > driver_nl80211 side:
> > 
> > --> sends data as is, done in bss_info_handler:
> > 	r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
> > 	r->level /= 100; /* mBm to dBm */
> > 	r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
> > 
> > Again explicitly says that has no quality data, sends only dBm or unspecified data;
> > 
> > 
> > 
> > NM side:
> > 
> > --> three strategies used (in wireless_qual_to_percent)
> > 	--> quality: (used with driver_wext), not reported by nl80211
> > 
> > 	--> dbm: used only if:
> > 		* valid and zero max_qual->level (but now set to -110....) 
> 
> IIRC non-zero max_qual->level was the indication that the driver wanted
> to use RSSI, not dBm.  Since the real "max" dBm is around 0 (ie, that's
> the highest signal strength you'll ever really see), max_qual->level
> meant the driver was reporting signal strength in dBm.  max_qual->level
> == -110 is kinda wrong, because that's the _minimum_ level, not the max.
This is very good point, a question for kernel developers, why it was
set as such? How about setting it to ?


> The noise floor is almost always around -100 dBm so setting
> max_qual->level is pretty useless.
> 
> This is *exactly* why 'qual' is there: so that the driver itself can
> figure out what the hell it's signal level is, and so that NM doesn't
> have to go around assuming stuff.
It appears as kernel developers want to drop quality calculations
altogether, and report everything in dBms (right?) 
This is also a consistent I think.

> 
> For WEXT reporting, mac80211 should really be constructing a 'qual'
> instead of leaving it 0.  Then we don't have ambiguities with dBm, RSSI,
> unspec, etc.
It does, but driver_nl80211 doesn't use wext that is.


Also a recent conversation on linux-wireless indicated that noise level
is a property of the wireless card, so I think we won't see them in scan
results any time soon.


Best regards,
Maxim Levitsky


^ permalink raw reply

* Re: [PATCH] ar9170usb: add mode-switching for AVM Fritz!WLAN USB N devices in cdrom mode
From: Alan Cox @ 2009-11-02 22:39 UTC (permalink / raw)
  To: Dan Williams; +Cc: Matthew Dharm, Frank Schaefer, linux-wireless, linux-usb
In-Reply-To: <1257198124.1027.63.camel@localhost.localdomain>

> Maybe we can get the kernel drivers to expose the information we need
> (maybe even an 'eject' attribute in sysfs or something) and then we just
> have to write udev rules instead of having a whole bunch of libusb junk
> in userspace?  Would that preserve the policy-always-in-userspace
> requirement yet keep the code to drive the hardware in kernel space
> where it really belongs?

Or put the magic strings in the kernel with a translation hook for the
eject request ? That would keep policy and method in the right places.
You ask the kernel to eject, it hides the magic weirdness.

^ permalink raw reply

* Re: [PATCH] ar9170usb: add mode-switching for AVM Fritz!WLAN USB N devices in cdrom mode
From: Christian Lamparter @ 2009-11-02 22:23 UTC (permalink / raw)
  To: Dan Williams
  Cc: Alan Cox, Frank Schaefer, Matthew Dharm, linux-wireless,
	linux-usb
In-Reply-To: <1257198359.1027.67.camel@localhost.localdomain>

On Monday 02 November 2009 22:45:59 Dan Williams wrote:
> On Mon, 2009-11-02 at 21:05 +0000, Alan Cox wrote:
> > > apparently do use the driver CD thing to send Linux drivers and software
> > > to a few clients.  But by and large, the driver CD is completely
> > > useless.
> > 
> > And then every so often you need to rummage around the driver CD image to
> > extract the APN or other data you need to make your modem work. At which
> > point you end up having to recompile the kernel to get it. Very annoying
> > given it could be trivially done properly in user space.
>
> Maybe there's a better way as I said a bit lower in the thread; could we
> put the logic for ejection into the driver (and not usb_modeswitch or
> whatever) but put the decision into userspace in udev?
> 
> Right now the kernel drivers know what hardware they support, and that's
> a great place to also put how to eject the fake driver CD.  So the
> mechanism could live in the kernel still (instead of in usb_modeswitch
> in userspace) while the actual decision still gets made in userspace
> with udev rules.  The rules would say something like "if this USB
> storage device has an 'fakecd' attribute, then touch the 'ejectmeharder'
> attribute" instead of complex rules to run usb_modeswitch that duplicate
> all the device IDs in userspace.  If you need to rummage around on the
> driver CD for whatever reason, you disable the udev rule.  Maybe?
> 
> I simply hate the duplication of all the device IDs with one set in the
> kernel and one set in userspace because it's pretty pointless and makes
> twice the work when new hardware comes out.
>
well, there's more to Alan's theory here.

AVM provides a beta firmware [1] which allows the user to but the stick into
the mass storage mode again and stream the data over WLAN connection. 
(of course, you'll need a special AP which supports this)

[1]: (german only, they haven't bothered to do a translation)
http://www.avm.de/de/Service/Service-Portale/Service-Portal/Labor/7270_streaming_stick/labor_start_streaming_stick.php

Of course, I haven't tested, or even seen such setup yet.
But it appears to be working (based on google).

Therefore, it might be a good idea to start a new user app,
which does this 3-way usb-mode switching for these devices.

Regards,	
	Chr

^ permalink raw reply

* Re: pull request: wireless-2.6 2009-11-02
From: Johannes Berg @ 2009-11-02 21:59 UTC (permalink / raw)
  To: John W. Linville; +Cc: davem, linux-wireless, netdev, linux-kernel
In-Reply-To: <20091102214022.GM14046@tuxdriver.com>

[-- Attachment #1: Type: text/plain, Size: 258 bytes --]

On Mon, 2009-11-02 at 16:40 -0500, John W. Linville wrote:

> There are several from Johannes -- I'm sure there was sake involved...  :-)

More likely there was sake involved when I did that patch adding that
NULL-ptr deref!

Thanks :)

johannes


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply

* Re: HCCA issue
From: isabel @ 2009-11-02 21:53 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <b37aee660911021351i7f4f57c3xf6fb466e2084bb5e@mail.gmail.com>

2009/11/2 isabel <isabel@porlapuertadeatras.net>
>
> Hi all,
>
> This is my first message in this list.. so.. hello all.
>
> I am diving into 802.11 standar... and I would like to implement some features of 802.11e, like HCCA..
> I know that I am not the first person trying that..
>
> The idea is implement a scheduler at AP level, which schedule traffic based on the stream received.
> My question is if all devices (Atheros) could implement that. I would like to modify flags on demand, and read the complet stream at AP level.
> I do not know if it is clear or not.. hope you understand me, if not I will explain it better.
>
> Thanks and regards.
>
>

^ permalink raw reply

* Re: [PATCH] ar9170usb: add mode-switching for AVM Fritz!WLAN USB N devices in cdrom mode
From: Dan Williams @ 2009-11-02 21:45 UTC (permalink / raw)
  To: Alan Cox; +Cc: Frank Schaefer, Matthew Dharm, linux-wireless, linux-usb
In-Reply-To: <20091102210519.7d309fb9@lxorguk.ukuu.org.uk>

On Mon, 2009-11-02 at 21:05 +0000, Alan Cox wrote:
> > apparently do use the driver CD thing to send Linux drivers and software
> > to a few clients.  But by and large, the driver CD is completely
> > useless.
> 
> And then every so often you need to rummage around the driver CD image to
> extract the APN or other data you need to make your modem work. At which
> point you end up having to recompile the kernel to get it. Very annoying
> given it could be trivially done properly in user space.

Maybe there's a better way as I said a bit lower in the thread; could we
put the logic for ejection into the driver (and not usb_modeswitch or
whatever) but put the decision into userspace in udev?

Right now the kernel drivers know what hardware they support, and that's
a great place to also put how to eject the fake driver CD.  So the
mechanism could live in the kernel still (instead of in usb_modeswitch
in userspace) while the actual decision still gets made in userspace
with udev rules.  The rules would say something like "if this USB
storage device has an 'fakecd' attribute, then touch the 'ejectmeharder'
attribute" instead of complex rules to run usb_modeswitch that duplicate
all the device IDs in userspace.  If you need to rummage around on the
driver CD for whatever reason, you disable the udev rule.  Maybe?

I simply hate the duplication of all the device IDs with one set in the
kernel and one set in userspace because it's pretty pointless and makes
twice the work when new hardware comes out.

Dan


^ permalink raw reply

* pull request: wireless-2.6 2009-11-02
From: John W. Linville @ 2009-11-02 21:40 UTC (permalink / raw)
  To: davem; +Cc: linux-wireless, netdev, linux-kernel

Dave,

Another collection of fixes intended for 2.6.32...several
(almost-)one-liners, a b43 bounce-buffer fix,  and a couple of USB IDs.
There are several from Johannes -- I'm sure there was sake involved...  :-)

Please let me know if there are problems!

John

---

Individual patches are available here:

	http://www.kernel.org/pub/linux/kernel/people/linville/wireless-2.6/

---

The following changes since commit 63ca2d74ea4f9c7a7ac082c915609a7b224908e7:
  Ken Kawasaki (1):
        pcnet_cs: add cis of PreMax PE-200 ethernet pcmcia card

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git master

David Woodhouse (1):
      libertas if_usb: Fix crash on 64-bit machines

Johannes Berg (5):
      mac80211: fix BSS leak
      mac80211: fix addba timer
      mac80211: fix reason code output endianness
      cfg80211: fix NULL ptr deref
      mac80211: check interface is down before type change

Luis R. Rodriguez (1):
      ath9k: fix misplaced semicolon on rate control

Michael Buesch (1):
      b43: Fix DMA TX bounce buffer copying

Xose Vazquez Perez (1):
      rt73usb.c : more ids

Zhu Yi (1):
      ipw2200: fix oops on missing firmware

 drivers/net/wireless/ath/ath9k/rc.c          |    2 +-
 drivers/net/wireless/b43/dma.c               |   15 +++++++++++++--
 drivers/net/wireless/ipw2x00/ipw2100.c       |    5 ++++-
 drivers/net/wireless/ipw2x00/ipw2200.c       |    2 ++
 drivers/net/wireless/ipw2x00/libipw.h        |    1 +
 drivers/net/wireless/ipw2x00/libipw_module.c |   14 +++++++++-----
 drivers/net/wireless/libertas/if_usb.c       |    2 +-
 drivers/net/wireless/rt2x00/rt73usb.c        |    5 +++++
 net/mac80211/agg-tx.c                        |   19 ++++++++++++-------
 net/mac80211/cfg.c                           |    6 +++---
 net/mac80211/ht.c                            |    2 +-
 net/mac80211/ibss.c                          |    6 ++++--
 net/wireless/sme.c                           |    7 +++++--
 13 files changed, 61 insertions(+), 25 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 16a2717..1895d63 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -679,7 +679,7 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
 		return rate;
 
 	if (rate_table->info[rate].valid_single_stream &&
-	    !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG));
+	    !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))
 		return rate;
 
 	/* This should not happen */
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 8701034..de4e804 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -1157,8 +1157,9 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
 }
 
 static int dma_tx_fragment(struct b43_dmaring *ring,
-			   struct sk_buff *skb)
+			   struct sk_buff **in_skb)
 {
+	struct sk_buff *skb = *in_skb;
 	const struct b43_dma_ops *ops = ring->ops;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	u8 *header;
@@ -1224,8 +1225,14 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
 		}
 
 		memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+		memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb));
+		bounce_skb->dev = skb->dev;
+		skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb));
+		info = IEEE80211_SKB_CB(bounce_skb);
+
 		dev_kfree_skb_any(skb);
 		skb = bounce_skb;
+		*in_skb = bounce_skb;
 		meta->skb = skb;
 		meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
 		if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
@@ -1355,7 +1362,11 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
 	 * static, so we don't need to store it per frame. */
 	ring->queue_prio = skb_get_queue_mapping(skb);
 
-	err = dma_tx_fragment(ring, skb);
+	/* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing
+	 * into the skb data or cb now. */
+	hdr = NULL;
+	info = NULL;
+	err = dma_tx_fragment(ring, &skb);
 	if (unlikely(err == -ENOKEY)) {
 		/* Drop this packet, as we don't have the encryption key
 		 * anymore and must not transmit it unencrypted. */
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 240cff1..a741d37 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -6325,8 +6325,10 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
 
       fail:
 	if (dev) {
-		if (registered)
+		if (registered) {
+			unregister_ieee80211(priv->ieee);
 			unregister_netdev(dev);
+		}
 
 		ipw2100_hw_stop_adapter(priv);
 
@@ -6383,6 +6385,7 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev)
 		/* Unregister the device first - this results in close()
 		 * being called if the device is open.  If we free storage
 		 * first, then close() will crash. */
+		unregister_ieee80211(priv->ieee);
 		unregister_netdev(dev);
 
 		/* ipw2100_down will ensure that there is no more pending work
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 8d58e6e..04341a2 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -11821,6 +11821,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
 		if (err) {
 			IPW_ERROR("Failed to register promiscuous network "
 				  "device (error %d).\n", err);
+			unregister_ieee80211(priv->ieee);
 			unregister_netdev(priv->net_dev);
 			goto out_remove_sysfs;
 		}
@@ -11871,6 +11872,7 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev)
 
 	mutex_unlock(&priv->mutex);
 
+	unregister_ieee80211(priv->ieee);
 	unregister_netdev(priv->net_dev);
 
 	if (priv->rxq) {
diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h
index bf45391..f42ade6 100644
--- a/drivers/net/wireless/ipw2x00/libipw.h
+++ b/drivers/net/wireless/ipw2x00/libipw.h
@@ -1020,6 +1020,7 @@ static inline int libipw_is_cck_rate(u8 rate)
 /* ieee80211.c */
 extern void free_ieee80211(struct net_device *dev, int monitor);
 extern struct net_device *alloc_ieee80211(int sizeof_priv, int monitor);
+extern void unregister_ieee80211(struct libipw_device *ieee);
 extern int libipw_change_mtu(struct net_device *dev, int new_mtu);
 
 extern void libipw_networks_age(struct libipw_device *ieee,
diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c
index a0e9f6a..be5b809 100644
--- a/drivers/net/wireless/ipw2x00/libipw_module.c
+++ b/drivers/net/wireless/ipw2x00/libipw_module.c
@@ -235,16 +235,19 @@ void free_ieee80211(struct net_device *dev, int monitor)
 	libipw_networks_free(ieee);
 
 	/* free cfg80211 resources */
-	if (!monitor) {
-		wiphy_unregister(ieee->wdev.wiphy);
-		kfree(ieee->a_band.channels);
-		kfree(ieee->bg_band.channels);
+	if (!monitor)
 		wiphy_free(ieee->wdev.wiphy);
-	}
 
 	free_netdev(dev);
 }
 
+void unregister_ieee80211(struct libipw_device *ieee)
+{
+	wiphy_unregister(ieee->wdev.wiphy);
+	kfree(ieee->a_band.channels);
+	kfree(ieee->bg_band.channels);
+}
+
 #ifdef CONFIG_LIBIPW_DEBUG
 
 static int debug = 0;
@@ -330,3 +333,4 @@ module_init(libipw_init);
 
 EXPORT_SYMBOL(alloc_ieee80211);
 EXPORT_SYMBOL(free_ieee80211);
+EXPORT_SYMBOL(unregister_ieee80211);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 92bc8c5..3fac4ef 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -508,7 +508,7 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
 	/* Fill the receive configuration URB and initialise the Rx call back */
 	usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
 			  usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
-			  (void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET),
+			  skb->data + IPFIELD_ALIGN_OFFSET,
 			  MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
 			  cardp);
 
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index b8f5ee3..14e7bb2 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2389,10 +2389,13 @@ static struct usb_device_id rt73usb_device_table[] = {
 	{ USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) },
 	{ USB_DEVICE(0x13b1, 0x0028), USB_DEVICE_DATA(&rt73usb_ops) },
 	/* MSI */
+	{ USB_DEVICE(0x0db0, 0x4600), USB_DEVICE_DATA(&rt73usb_ops) },
 	{ USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) },
 	{ USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) },
 	{ USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) },
 	{ USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Ovislink */
+	{ USB_DEVICE(0x1b75, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) },
 	/* Ralink */
 	{ USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) },
 	{ USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },
@@ -2420,6 +2423,8 @@ static struct usb_device_id rt73usb_device_table[] = {
 	/* Planex */
 	{ USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) },
 	{ USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* WideTell */
+	{ USB_DEVICE(0x7167, 0x3840), USB_DEVICE_DATA(&rt73usb_ops) },
 	/* Zcom */
 	{ USB_DEVICE(0x0cde, 0x001c), USB_DEVICE_DATA(&rt73usb_ops) },
 	/* ZyXEL */
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index bd765f3..b09948c 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -666,26 +666,25 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
 
 	state = &sta->ampdu_mlme.tid_state_tx[tid];
 
+	del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+
 	spin_lock_bh(&sta->lock);
 
-	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
-		spin_unlock_bh(&sta->lock);
-		return;
-	}
+	if (!(*state & HT_ADDBA_REQUESTED_MSK))
+		goto timer_still_needed;
 
 	if (mgmt->u.action.u.addba_resp.dialog_token !=
 		sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
-		spin_unlock_bh(&sta->lock);
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
-		return;
+		goto timer_still_needed;
 	}
 
-	del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
+
 	if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
 			== WLAN_STATUS_SUCCESS) {
 		u8 curstate = *state;
@@ -699,5 +698,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
 	} else {
 		___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
 	}
+
+	goto out;
+
+ timer_still_needed:
+	add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+ out:
 	spin_unlock_bh(&sta->lock);
 }
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5608f6c..7b5131b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -72,6 +72,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
 	struct ieee80211_sub_if_data *sdata;
 	int ret;
 
+	if (netif_running(dev))
+		return -EBUSY;
+
 	if (!nl80211_type_check(type))
 		return -EINVAL;
 
@@ -81,9 +84,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
 	if (ret)
 		return ret;
 
-	if (netif_running(sdata->dev))
-		return -EBUSY;
-
 	if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
 		ieee80211_sdata_set_mesh_id(sdata,
 					    params->mesh_id_len,
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 0891bfb..48ef1a2 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -153,7 +153,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata,
 	if (net_ratelimit())
 		printk(KERN_DEBUG "delba from %pM (%s) tid %d reason code %d\n",
 			mgmt->sa, initiator ? "initiator" : "recipient", tid,
-			mgmt->u.action.u.delba.reason_code);
+			le16_to_cpu(mgmt->u.action.u.delba.reason_code));
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
 	if (initiator == WLAN_BACK_INITIATOR)
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index ca8ecce..f1362f3 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -73,6 +73,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_mgmt *mgmt;
 	u8 *pos;
 	struct ieee80211_supported_band *sband;
+	struct cfg80211_bss *bss;
 	u32 bss_change;
 	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
 
@@ -177,8 +178,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 	mod_timer(&ifibss->timer,
 		  round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL));
 
-	cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel,
-				  mgmt, skb->len, 0, GFP_KERNEL);
+	bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel,
+					mgmt, skb->len, 0, GFP_KERNEL);
+	cfg80211_put_bss(bss);
 	cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
 }
 
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index ece378d..9f0b280 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -165,7 +165,7 @@ void cfg80211_conn_work(struct work_struct *work)
 	struct cfg80211_registered_device *rdev =
 		container_of(work, struct cfg80211_registered_device, conn_work);
 	struct wireless_dev *wdev;
-	u8 bssid[ETH_ALEN];
+	u8 bssid_buf[ETH_ALEN], *bssid = NULL;
 
 	rtnl_lock();
 	cfg80211_lock_rdev(rdev);
@@ -181,7 +181,10 @@ void cfg80211_conn_work(struct work_struct *work)
 			wdev_unlock(wdev);
 			continue;
 		}
-		memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN);
+		if (wdev->conn->params.bssid) {
+			memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN);
+			bssid = bssid_buf;
+		}
 		if (cfg80211_conn_do_work(wdev))
 			__cfg80211_connect_result(
 					wdev->netdev, bssid,
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply related

* Re: [RFC] mac80211: make ieee80211_find_sta per virtual interface
From: Luis R. Rodriguez @ 2009-11-02 21:42 UTC (permalink / raw)
  To: Luis R. Rodriguez
  Cc: Johannes Berg, linux-wireless, Jouni Malinen, Sujith Manoharan,
	Vasanthakumar Thiagarajan, Senthil Balasubramanian
In-Reply-To: <43e72e890910300802v25ba6211s4e9302dd1968230e@mail.gmail.com>

On Fri, Oct 30, 2009 at 08:02:26AM -0700, Luis R. Rodriguez wrote:
> On Fri, Oct 30, 2009 at 2:58 AM, Johannes Berg
> <johannes@sipsolutions.net> wrote:
> > Since we have a TODO item to make all station
> > management dependent on virtual interfaces, I
> > figured I'd start with pushing such a change
> > to drivers before more drivers use this kind
> > of functionality...
> >
> > The iwlwifi bits are easy, but I don't know
> > what to do about the ath9k bits. Any ideas?
> 
> > --- wireless-testing.orig/drivers/net/wireless/ath/ath9k/xmit.c 2009-10-30 10:54:10.000000000 +0100
> > +++ wireless-testing/drivers/net/wireless/ath/ath9k/xmit.c      2009-10-30 10:55:48.000000000 +0100
> > @@ -282,7 +282,7 @@ static void ath_tx_complete_aggr(struct
> >
> >        rcu_read_lock();
> >
> > -       sta = ieee80211_find_sta(sc->hw, hdr->addr1);
> > +       sta = ieee80211_find_sta(/*??????*/, hdr->addr1);
> 
> Not sure but I just wanted to point out the that the sc->hw above here
> was wrong anyway for virtual wiphy support, this should instead
> probably look for the aphy with ath_get_virt_hw() as is done with
> ath_rx_prepare().

And upon further investigation one way to do this is something as below. I did this
as a test as I needed to answer the question of "who does this skb belong to" for
virtual wiphy purposes. The question of who it belongs to is not that important but
the more important thing is to determine the appropriate ieee80211_hw and the mode
of operation the hw should use to behave for the skb. ath9k uses the sc->sc_ah->opmode
in many places and it was to be determined how we'd update this for virtual wiphys.
To answer that you need to determine either the minimum hw configuration your device
needs to operate under to allow all current virtual wiphys to operate properly
or just determine the vif we are to use. Either way it turns out these questions
are not easy to answer from the driver.

A simple question like: "do we have monitor vif?" is not an easy question to answer
for mac80211 drivers as such, as this patch should illustrate, we should perhaps
consider moving more of the virtual wiphy implementation to mac80211/cfg80211 or
as you have put it -- just bring the vif capability to be on its own channel.

diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 330cd3b..9c41071 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -17,23 +17,29 @@
 #include "ath9k.h"
 
 static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc,
-					     struct ieee80211_hdr *hdr)
+					     struct ieee80211_hdr *hdr,
+					     struct ieee80211_vif **vif)
 {
 	struct ieee80211_hw *hw = sc->pri_wiphy->hw;
 	int i;
 
+	*vif = ieee80211_get_vif_by_mac_atomic(hw, hdr->addr1);
+	if (*vif)
+		return hw;
+
 	spin_lock_bh(&sc->wiphy_lock);
 	for (i = 0; i < sc->num_sec_wiphy; i++) {
 		struct ath_wiphy *aphy = sc->sec_wiphy[i];
-		if (aphy == NULL)
+		if (!aphy)
 			continue;
-		if (compare_ether_addr(hdr->addr1, aphy->hw->wiphy->perm_addr)
-		    == 0) {
+		*vif = ieee80211_get_vif_by_mac_atomic(aphy->hw, hdr->addr1);
+		if (*vif) {
 			hw = aphy->hw;
 			break;
 		}
 	}
 	spin_unlock_bh(&sc->wiphy_lock);
+
 	return hw;
 }
 
@@ -662,6 +668,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 	struct ieee80211_rx_status rx_status;
 	struct ath_hw *ah = sc->sc_ah;
 	struct ath_common *common = ath9k_hw_common(ah);
+	struct ieee80211_vif *vif;
 	/*
 	 * The hw can techncically differ from common->hw when using ath9k
 	 * virtual wiphy so to account for that we iterate over the active
@@ -748,7 +755,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 				DMA_FROM_DEVICE);
 
 		hdr = (struct ieee80211_hdr *) skb->data;
-		hw = ath_get_virt_hw(sc, hdr);
+		hw = ath_get_virt_hw(sc, hdr, &vif);
 
 		/*
 		 * If we're asked to flush receive queue, directly
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e12293e..1d2bb0a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1999,6 +1999,12 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
 						    struct ieee80211_vif *vif),
 						void *data);
 
+struct ieee80211_vif *ieee80211_get_vif_by_mac(struct ieee80211_hw *hw,
+					       u8 *mac);
+
+struct ieee80211_vif *ieee80211_get_vif_by_mac_atomic(struct ieee80211_hw *hw,
+					       u8 *mac);
+
 /**
  * ieee80211_queue_work - add work onto the mac80211 workqueue
  *
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index aedbaaa..f3f5a8b 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -511,6 +511,107 @@ void ieee80211_iterate_active_interfaces_atomic(
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
 
+static struct ieee80211_vif *ieee80211_get_first_mon_vif(struct ieee80211_hw *hw)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_vif *vif = NULL;
+
+	if (likely(!local->monitors && local->cooked_mntrs++))
+		return NULL;
+
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+			vif = &sdata->vif;
+			break;
+		}
+	}
+
+	return vif;
+}
+
+struct ieee80211_vif *ieee80211_get_vif_by_mac(struct ieee80211_hw *hw,
+					       u8 *mac)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_vif *vif = NULL;
+
+	mutex_lock(&local->iflist_mtx);
+
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		switch (sdata->vif.type) {
+		case __NL80211_IFTYPE_AFTER_LAST:
+		case NL80211_IFTYPE_UNSPECIFIED:
+		case NL80211_IFTYPE_MONITOR:
+		case NL80211_IFTYPE_AP_VLAN:
+			continue;
+		case NL80211_IFTYPE_AP:
+		case NL80211_IFTYPE_STATION:
+		case NL80211_IFTYPE_ADHOC:
+		case NL80211_IFTYPE_WDS:
+		case NL80211_IFTYPE_MESH_POINT:
+			break;
+		}
+
+		if (compare_ether_addr(mac, sdata->dev->dev_addr) == 0) {
+			vif = &sdata->vif;
+			break;
+		}
+	}
+
+	if (!vif) {
+		vif = ieee80211_get_first_mon_vif(hw);
+		WARN_ON(!vif);
+	}
+
+	mutex_unlock(&local->iflist_mtx);
+
+	return vif;
+}
+EXPORT_SYMBOL_GPL(ieee80211_get_vif_by_mac);
+
+struct ieee80211_vif *ieee80211_get_vif_by_mac_atomic(struct ieee80211_hw *hw,
+						      u8 *mac)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_vif *vif = NULL;
+
+	rcu_read_lock();
+
+	list_for_each_entry(sdata, &local->interfaces, list) {
+		switch (sdata->vif.type) {
+		case __NL80211_IFTYPE_AFTER_LAST:
+		case NL80211_IFTYPE_UNSPECIFIED:
+		case NL80211_IFTYPE_MONITOR:
+		case NL80211_IFTYPE_AP_VLAN:
+			continue;
+		case NL80211_IFTYPE_AP:
+		case NL80211_IFTYPE_STATION:
+		case NL80211_IFTYPE_ADHOC:
+		case NL80211_IFTYPE_WDS:
+		case NL80211_IFTYPE_MESH_POINT:
+			break;
+		}
+
+		if (compare_ether_addr(mac, sdata->dev->dev_addr) == 0) {
+			vif = &sdata->vif;
+			break;
+		}
+	}
+
+	if (!vif) {
+		vif = ieee80211_get_first_mon_vif(hw);
+		WARN_ON(!vif);
+	}
+
+	rcu_read_unlock();
+
+	return vif;
+}
+EXPORT_SYMBOL_GPL(ieee80211_get_vif_by_mac_atomic);
+
 /*
  * Nothing should have been stuffed into the workqueue during
  * the suspend->resume cycle. If this WARN is seen then there

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox