Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH 2/7] mac80211: fix tid_agg_rx NULL dereference
From: Luca Coelho @ 2016-10-18 20:12 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Johannes Berg
In-Reply-To: <20161018201213.18873-1-luca@coelho.fi>

From: Johannes Berg <johannes.berg@intel.com>

On drivers setting the SUPPORTS_REORDERING_BUFFER hardware flag,
we crash when the peer sends an AddBA request while we already
have a session open on the seame TID; this is because on those
drivers, the tid_agg_rx is left NULL even though the session is
valid, and the agg_session_valid bit is set.

To fix this, store the dialog tokens outside the tid_agg_rx to
be able to compare them to the received AddBA request.

Fixes: f89e07d4cf26 ("mac80211: agg-rx: refuse ADDBA Request with timeout update")
Reported-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/agg-rx.c      | 8 ++------
 net/mac80211/debugfs_sta.c | 2 +-
 net/mac80211/sta_info.h    | 4 ++--
 3 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index f6749dc..3b5fd41 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -315,11 +315,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
 	mutex_lock(&sta->ampdu_mlme.mtx);
 
 	if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
-		tid_agg_rx = rcu_dereference_protected(
-				sta->ampdu_mlme.tid_rx[tid],
-				lockdep_is_held(&sta->ampdu_mlme.mtx));
-
-		if (tid_agg_rx->dialog_token == dialog_token) {
+		if (sta->ampdu_mlme.tid_rx_token[tid] == dialog_token) {
 			ht_dbg_ratelimited(sta->sdata,
 					   "updated AddBA Req from %pM on tid %u\n",
 					   sta->sta.addr, tid);
@@ -396,7 +392,6 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
 	}
 
 	/* update data */
-	tid_agg_rx->dialog_token = dialog_token;
 	tid_agg_rx->ssn = start_seq_num;
 	tid_agg_rx->head_seq_num = start_seq_num;
 	tid_agg_rx->buf_size = buf_size;
@@ -418,6 +413,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
 	if (status == WLAN_STATUS_SUCCESS) {
 		__set_bit(tid, sta->ampdu_mlme.agg_session_valid);
 		__clear_bit(tid, sta->ampdu_mlme.unexpected_agg);
+		sta->ampdu_mlme.tid_rx_token[tid] = dialog_token;
 	}
 	mutex_unlock(&sta->ampdu_mlme.mtx);
 
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index a2fcdb4..14ec63a 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -205,7 +205,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
 		p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i);
 		p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", !!tid_rx);
 		p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
-				tid_rx ? tid_rx->dialog_token : 0);
+				tid_rx ? sta->ampdu_mlme.tid_rx_token[i] : 0);
 		p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
 				tid_rx ? tid_rx->ssn : 0);
 
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index ed5fcb9..dd06ef0 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -184,7 +184,6 @@ struct tid_ampdu_tx {
  * @ssn: Starting Sequence Number expected to be aggregated.
  * @buf_size: buffer size for incoming A-MPDUs
  * @timeout: reset timer value (in TUs).
- * @dialog_token: dialog token for aggregation session
  * @rcu_head: RCU head used for freeing this struct
  * @reorder_lock: serializes access to reorder buffer, see below.
  * @auto_seq: used for offloaded BA sessions to automatically pick head_seq_and
@@ -213,7 +212,6 @@ struct tid_ampdu_rx {
 	u16 ssn;
 	u16 buf_size;
 	u16 timeout;
-	u8 dialog_token;
 	bool auto_seq;
 	bool removed;
 };
@@ -225,6 +223,7 @@ struct tid_ampdu_rx {
  *	to tid_tx[idx], which are protected by the sta spinlock)
  *	tid_start_tx is also protected by sta->lock.
  * @tid_rx: aggregation info for Rx per TID -- RCU protected
+ * @tid_rx_token: dialog tokens for valid aggregation sessions
  * @tid_rx_timer_expired: bitmap indicating on which TIDs the
  *	RX timer expired until the work for it runs
  * @tid_rx_stop_requested:  bitmap indicating which BA sessions per TID the
@@ -243,6 +242,7 @@ struct sta_ampdu_mlme {
 	struct mutex mtx;
 	/* rx */
 	struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS];
+	u8 tid_rx_token[IEEE80211_NUM_TIDS];
 	unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
 	unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
 	unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
-- 
2.9.3

^ permalink raw reply related

* [PATCH 3/7] mac80211: improve RX aggregation data in debugfs
From: Luca Coelho @ 2016-10-18 20:12 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Johannes Berg
In-Reply-To: <20161018201213.18873-1-luca@coelho.fi>

From: Johannes Berg <johannes.berg@intel.com>

When the driver sets the SUPPORTS_REORDERING_BUFFER hardware flag,
the debugfs data for RX aggregation sessions won't even indicate
that a session is open. Since the previous fix to store the dialog
token separately, we can indicate that it's open and add the token
so that there's at least some data (ssn is not available.)

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/debugfs_sta.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 14ec63a..f6003b8 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -199,13 +199,18 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
 		       "TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tpending\n");
 
 	for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
+		bool tid_rx_valid;
+
 		tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]);
 		tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]);
+		tid_rx_valid = test_bit(i, sta->ampdu_mlme.agg_session_valid);
 
 		p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i);
-		p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", !!tid_rx);
+		p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
+			       tid_rx_valid);
 		p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
-				tid_rx ? sta->ampdu_mlme.tid_rx_token[i] : 0);
+			       tid_rx_valid ?
+					sta->ampdu_mlme.tid_rx_token[i] : 0);
 		p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
 				tid_rx ? tid_rx->ssn : 0);
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH 4/7] mac80211: allow the driver not to pass the tid to ieee80211_sta_uapsd_trigger
From: Luca Coelho @ 2016-10-18 20:12 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Emmanuel Grumbach, Luca Coelho
In-Reply-To: <20161018201213.18873-1-luca@coelho.fi>

From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>

iwlwifi will check internally that the tid maps to an AC
that is trigger enabled, but can't know what tid exactly.
Allow the driver to pass a generic tid and make mac80211
assume that a trigger frame was received.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 include/net/mac80211.h | 4 ++++
 net/mac80211/rx.c      | 5 +++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e50c9e0..f3dbada 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4087,6 +4087,10 @@ void ieee80211_sta_pspoll(struct ieee80211_sta *sta);
  * This must be used in conjunction with ieee80211_sta_ps_transition()
  * and possibly ieee80211_sta_pspoll(); calls to all three must be
  * serialized.
+ * %IEEE80211_NUM_TIDS can be passed as the tid if the tid is unknown.
+ * In this case, mac80211 will not check that this tid maps to an AC
+ * that is trigger enabled and assume that the caller did the proper
+ * checks.
  */
 void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *sta, u8 tid);
 
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index fc08a50..837d562 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1394,13 +1394,14 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
 	u8 ac = ieee802_1d_to_ac[tid & 7];
 
 	/*
-	 * If this AC is not trigger-enabled do nothing.
+	 * If this AC is not trigger-enabled do nothing unless the
+	 * driver is calling us after it already checked.
 	 *
 	 * NB: This could/should check a separate bitmap of trigger-
 	 * enabled queues, but for now we only implement uAPSD w/o
 	 * TSPEC changes to the ACs, so they're always the same.
 	 */
-	if (!(sta->sta.uapsd_queues & BIT(ac)))
+	if (!(sta->sta.uapsd_queues & BIT(ac)) && tid != IEEE80211_NUM_TIDS)
 		return;
 
 	/* if we are in a service period, do nothing */
-- 
2.9.3

^ permalink raw reply related

* [PATCH 5/7] mac80211: add a HW flag for supporting HW TX fragmentation
From: Luca Coelho @ 2016-10-18 20:12 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Sara Sharon, Luca Coelho
In-Reply-To: <20161018201213.18873-1-luca@coelho.fi>

From: Sara Sharon <sara.sharon@intel.com>

Currently mac80211 determines whether HW does fragmentation
by checking whether the set_frag_threshold callback is set
or not.
However, some drivers may want to set the HW fragmentation
capability depending on HW generation.
Allow this by checking a HW flag instead of checking the
callback.

Signed-off-by: Sara Sharon <sara.sharon@intel.com>
[added the flag to ath10k and wlcore]
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/ath/ath10k/mac.c |  1 +
 drivers/net/wireless/ti/wlcore/main.c |  1 +
 include/net/mac80211.h                | 10 ++++++++--
 net/mac80211/debugfs.c                |  1 +
 net/mac80211/main.c                   |  4 ++++
 net/mac80211/tx.c                     |  4 ++--
 net/mac80211/wpa.c                    |  2 +-
 7 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index 76297d6..e322b6d 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -7881,6 +7881,7 @@ int ath10k_mac_register(struct ath10k *ar)
 	ieee80211_hw_set(ar->hw, WANT_MONITOR_VIF);
 	ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA);
 	ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
+	ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
 
 	if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags))
 		ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL);
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 471521a..9f39c6c 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -6086,6 +6086,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
 	ieee80211_hw_set(wl->hw, SUPPORTS_DYNAMIC_PS);
 	ieee80211_hw_set(wl->hw, SIGNAL_DBM);
 	ieee80211_hw_set(wl->hw, SUPPORTS_PS);
+	ieee80211_hw_set(wl->hw, SUPPORTS_TX_FRAG);
 
 	wl->hw->wiphy->cipher_suites = cipher_suites;
 	wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index f3dbada..a1a2702 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2025,6 +2025,10 @@ struct ieee80211_txq {
  *	drivers, mac80211 packet loss mechanism will not be triggered and driver
  *	is completely depending on firmware event for station kickout.
  *
+ * @IEEE80211_HW_SUPPORTS_TX_FRAG: Hardware does fragmentation by itself.
+ *	The stack will not do fragmentation.
+ *	The callback for @set_frag_threshold should be set as well.
+ *
  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
  */
 enum ieee80211_hw_flags {
@@ -2066,6 +2070,7 @@ enum ieee80211_hw_flags {
 	IEEE80211_HW_TX_AMSDU,
 	IEEE80211_HW_TX_FRAG_LIST,
 	IEEE80211_HW_REPORTS_LOW_ACK,
+	IEEE80211_HW_SUPPORTS_TX_FRAG,
 
 	/* keep last, obviously */
 	NUM_IEEE80211_HW_FLAGS
@@ -3093,8 +3098,9 @@ enum ieee80211_reconfig_type {
  *	The callback must be atomic.
  *
  * @set_frag_threshold: Configuration of fragmentation threshold. Assign this
- *	if the device does fragmentation by itself; if this callback is
- *	implemented then the stack will not do fragmentation.
+ *	if the device does fragmentation by itself. Note that to prevent the
+ *	stack from doing fragmentation IEEE80211_HW_SUPPORTS_TX_FRAG
+ *	should be set as well.
  *	The callback can sleep.
  *
  * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index f56e2f4..e02ba42 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -210,6 +210,7 @@ static const char *hw_flag_names[] = {
 	FLAG(TX_AMSDU),
 	FLAG(TX_FRAG_LIST),
 	FLAG(REPORTS_LOW_ACK),
+	FLAG(SUPPORTS_TX_FRAG),
 #undef FLAG
 };
 
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 1075ac2..0d9163c 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -821,6 +821,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	     !local->ops->tdls_recv_channel_switch))
 		return -EOPNOTSUPP;
 
+	if (WARN_ON(ieee80211_hw_check(hw, SUPPORTS_TX_FRAG) &&
+		    !local->ops->set_frag_threshold))
+		return -EINVAL;
+
 	if (WARN_ON(local->hw.wiphy->interface_modes &
 			BIT(NL80211_IFTYPE_NAN) &&
 		    (!local->ops->start_nan || !local->ops->stop_nan)))
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 772e369..62ccaf6 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -934,7 +934,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
 	if (info->flags & IEEE80211_TX_CTL_DONTFRAG)
 		return TX_CONTINUE;
 
-	if (tx->local->ops->set_frag_threshold)
+	if (ieee80211_hw_check(&tx->local->hw, SUPPORTS_TX_FRAG))
 		return TX_CONTINUE;
 
 	/*
@@ -2800,7 +2800,7 @@ void ieee80211_check_fast_xmit(struct sta_info *sta)
 
 	/* fast-xmit doesn't handle fragmentation at all */
 	if (local->hw.wiphy->frag_threshold != (u32)-1 &&
-	    !local->ops->set_frag_threshold)
+	    !ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG))
 		goto out;
 
 	rcu_read_lock();
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index b48c1e1..c249345 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -57,7 +57,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
 
 	if (info->control.hw_key &&
 	    (info->flags & IEEE80211_TX_CTL_DONTFRAG ||
-	     tx->local->ops->set_frag_threshold) &&
+	     ieee80211_hw_check(&tx->local->hw, SUPPORTS_TX_FRAG)) &&
 	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) {
 		/* hwaccel - with no need for SW-generated MMIC */
 		return TX_CONTINUE;
-- 
2.9.3

^ permalink raw reply related

* [PATCH 6/7] mac80211: uapsd_queues is in QoS IE order
From: Luca Coelho @ 2016-10-18 20:12 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Emmanuel Grumbach, Luca Coelho
In-Reply-To: <20161018201213.18873-1-luca@coelho.fi>

From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>

The uapsd_queue field is in QoS IE order and not in
IEEE80211_AC_*'s order.
This means that mac80211 would get confused between
BK and BE which is certainly not such a big deal but
needs to be fixed.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 include/net/cfg80211.h     |  3 ++-
 include/net/mac80211.h     |  3 ++-
 net/mac80211/ieee80211_i.h |  2 ++
 net/mac80211/mlme.c        |  2 +-
 net/mac80211/rx.c          |  3 ++-
 net/mac80211/sta_info.c    | 13 ++++++++-----
 net/mac80211/util.c        |  7 +++++++
 7 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5000ec7..10a26f0 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4574,7 +4574,8 @@ void cfg80211_auth_timeout(struct net_device *dev, const u8 *addr);
  *	moves to cfg80211 in this call
  * @buf: authentication frame (header + body)
  * @len: length of the frame data
- * @uapsd_queues: bitmap of ACs configured to uapsd. -1 if n/a.
+ * @uapsd_queues: bitmap of queues configured for uapsd. Same format
+ *	as the AC bitmap in the QoS info field
  *
  * After being asked to associate via cfg80211_ops::assoc() the driver must
  * call either this function or cfg80211_auth_timeout().
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index a1a2702..b9b24ab 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1745,7 +1745,8 @@ struct ieee80211_sta_rates {
  * @drv_priv: data area for driver use, will always be aligned to
  *	sizeof(void *), size is determined in hw information.
  * @uapsd_queues: bitmap of queues configured for uapsd. Only valid
- *	if wme is supported.
+ *	if wme is supported. The bits order is like in
+ *	IEEE80211_WMM_IE_STA_QOSINFO_AC_*.
  * @max_sp: max Service Period. Only valid if wme is supported.
  * @bandwidth: current bandwidth the station can receive with
  * @rx_nss: in HT/VHT, the maximum number of spatial streams the
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 42d194a..b4e2b6c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -84,6 +84,8 @@ struct ieee80211_local;
 #define IEEE80211_DEFAULT_MAX_SP_LEN		\
 	IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL
 
+extern const u8 ieee80211_ac_to_qos_mask[IEEE80211_NUM_ACS];
+
 #define IEEE80211_DEAUTH_FRAME_LEN	(24 /* hdr */ + 2 /* reason */)
 
 #define IEEE80211_MAX_NAN_INSTANCE_ID 255
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7486f2d..c8d3a9b 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3193,7 +3193,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 		uapsd_queues = 0;
 		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
 			if (sdata->tx_conf[ac].uapsd)
-				uapsd_queues |= BIT(ac);
+				uapsd_queues |= ieee80211_ac_to_qos_mask[ac];
 	}
 
 	cfg80211_rx_assoc_resp(sdata->dev, bss, (u8 *)mgmt, len, uapsd_queues);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 837d562..21a8947 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1401,7 +1401,8 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
 	 * enabled queues, but for now we only implement uAPSD w/o
 	 * TSPEC changes to the ACs, so they're always the same.
 	 */
-	if (!(sta->sta.uapsd_queues & BIT(ac)) && tid != IEEE80211_NUM_TIDS)
+	if (!(sta->sta.uapsd_queues & ieee80211_ac_to_qos_mask[ac]) &&
+	    tid != IEEE80211_NUM_TIDS)
 		return;
 
 	/* if we are in a service period, do nothing */
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ab91e1e..236d47e 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -709,7 +709,7 @@ static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending)
 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
 		unsigned long tids;
 
-		if (ignore_for_tim & BIT(ac))
+		if (ignore_for_tim & ieee80211_ac_to_qos_mask[ac])
 			continue;
 
 		indicate_tim |= !skb_queue_empty(&sta->tx_filtered[ac]) ||
@@ -1389,7 +1389,7 @@ ieee80211_sta_ps_more_data(struct sta_info *sta, u8 ignored_acs,
 		return true;
 
 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-		if (ignored_acs & BIT(ac))
+		if (ignored_acs & ieee80211_ac_to_qos_mask[ac])
 			continue;
 
 		if (!skb_queue_empty(&sta->tx_filtered[ac]) ||
@@ -1414,7 +1414,7 @@ ieee80211_sta_ps_get_frames(struct sta_info *sta, int n_frames, u8 ignored_acs,
 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
 		unsigned long tids;
 
-		if (ignored_acs & BIT(ac))
+		if (ignored_acs & ieee80211_ac_to_qos_mask[ac])
 			continue;
 
 		tids = ieee80211_tids_for_ac(ac);
@@ -1482,7 +1482,7 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
 			BIT(find_highest_prio_tid(driver_release_tids));
 
 	if (skb_queue_empty(&frames) && !driver_release_tids) {
-		int tid;
+		int tid, ac;
 
 		/*
 		 * For PS-Poll, this can only happen due to a race condition
@@ -1500,7 +1500,10 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
 		 */
 
 		/* This will evaluate to 1, 3, 5 or 7. */
-		tid = 7 - ((ffs(~ignored_acs) - 1) << 1);
+		for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ac++)
+			if (ignored_acs & BIT(ac))
+				continue;
+		tid = 7 - 2 * ac;
 
 		ieee80211_send_null_response(sta, tid, reason, true, false);
 	} else if (!driver_release_tids) {
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 031273a..7f24bdc 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3452,3 +3452,10 @@ void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
 		*byte_cnt = txqi->tin.backlog_bytes + frag_bytes;
 }
 EXPORT_SYMBOL(ieee80211_txq_get_depth);
+
+const u8 ieee80211_ac_to_qos_mask[IEEE80211_NUM_ACS] = {
+	IEEE80211_WMM_IE_STA_QOSINFO_AC_VO,
+	IEEE80211_WMM_IE_STA_QOSINFO_AC_VI,
+	IEEE80211_WMM_IE_STA_QOSINFO_AC_BE,
+	IEEE80211_WMM_IE_STA_QOSINFO_AC_BK
+};
-- 
2.9.3

^ permalink raw reply related

* [PATCH 7/7] cfg80211: Call rdev_disconnect() when connection is in progress
From: Luca Coelho @ 2016-10-18 20:12 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Ilan Peer, Luca Coelho
In-Reply-To: <20161018201213.18873-1-luca@coelho.fi>

From: Ilan Peer <ilan.peer@intel.com>

On a disconnect request from user space, cfg80211 would have
called rdev_disconnect() only in case that 'current_bss' was set, i.e.,
connection has been established.

Change this, so rdev_disconnect() would be called also in case that
connection is in progress, so the connection attempt would be stopped.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 include/net/cfg80211.h | 7 ++++---
 net/wireless/sme.c     | 2 +-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 10a26f0..2bbbcc3 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2564,9 +2564,10 @@ struct cfg80211_nan_func {
  *	cases, the result of roaming is indicated with a call to
  *	cfg80211_roamed() or cfg80211_roamed_bss().
  *	(invoked with the wireless_dev mutex held)
- * @disconnect: Disconnect from the BSS/ESS. Once done, call
- *	cfg80211_disconnected().
- *	(invoked with the wireless_dev mutex held)
+ * @disconnect: Disconnect from the BSS/ESS or stop connection attempts if
+ *      connection is in progress. Once done, call cfg80211_disconnected() in
+ *      case connection was already established (invoked with the
+ *      wireless_dev mutex held), otherwise call cfg80211_connect_timeout().
  *
  * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call
  *	cfg80211_ibss_joined(), also call that function when changing BSSID due
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index a77db33..2b5bb38 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -1088,7 +1088,7 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 		err = cfg80211_sme_disconnect(wdev, reason);
 	else if (!rdev->ops->disconnect)
 		cfg80211_mlme_down(rdev, dev);
-	else if (wdev->current_bss)
+	else if (wdev->ssid_len)
 		err = rdev_disconnect(rdev, dev, reason);
 
 	return err;
-- 
2.9.3

^ permalink raw reply related

* Re: sequence diagrams in rst documentation
From: Jonathan Corbet @ 2016-10-18 23:52 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, linux-doc
In-Reply-To: <1476791021.6425.25.camel@sipsolutions.net>

On Tue, 18 Oct 2016 13:43:41 +0200
Johannes Berg <johannes@sipsolutions.net> wrote:

> > Example here:
> > https://johannes.sipsolutions.net/files/80211/mac80211.html#connection-flow  
> 
> Coming back to this - sadly, it appears that this software (blockdiag,
> seqdiag) is completely unmaintained, with open pull requests dating
> back to 2012 and the last commit dating back to 2015-08-22.
> 
> I'd want/need feature improvements in it too, but if I can't feed those
> back to upstream (since it appears dead), there's little point.
> 
> Perhaps we can ship plugins for this as part of the kernel sources?
> Shouldn't be too difficult to reimplement something like this, after
> all.

OK, I've read through all of this.  My thoughts, for whatever it's worth.

We already carry a few sphinx plugins in the kernel; there is room for
more if we *really* need them.  But...

 - Part of the idea behind switching over to sphinx was to be able to get
   away from maintaining our own formatting system.  Adding plugins to the
   kernel is a step away from that goal.  So I'd like to be sure that
   there's nothing that's part of standard sphinx that will do the job
   first.

That said, I think that requiring people to install plugins from contrib
sites or third-party repos may be even worse.  We don't want to put people
through misery just to format the docs.

In summary, I think we can consider taking on a module if it's what we
need to do the docs right.  And if somebody agrees to maintain it! :)

I've heard others say they would like better diagramming support.  Do you
think that, maybe, something like aafigure would do the trick?

	https://pythonhosted.org/sphinxcontrib-aafig/

I've not actually played with it at all, but I like the idea that we'd
have readable diagrams in the source docs as well...

jon

^ permalink raw reply

* [PATCH net-next 2/6] net: use core MTU range checking in wireless drivers
From: Jarod Wilson @ 2016-10-19  2:33 UTC (permalink / raw)
  To: linux-kernel
  Cc: Jarod Wilson, netdev, linux-wireless, Maya Erez, Simon Kelley,
	Stanislav Yakovlev
In-Reply-To: <20161019023333.15760-1-jarod@redhat.com>

- set max_mtu in wil6210 driver
- set max_mtu in atmel driver
- set min/max_mtu in cisco airo driver, remove airo_change_mtu
- set min/max_mtu in ipw2100/ipw2200 drivers, remove libipw_change_mtu
- set min/max_mtu in p80211netdev, remove wlan_change_mtu

CC: netdev@vger.kernel.org
CC: linux-wireless@vger.kernel.org
CC: Maya Erez <qca_merez@qca.qualcomm.com>
CC: Simon Kelley <simon@thekelleys.org.uk>
CC: Stanislav Yakovlev <stas.yakovlev@gmail.com>
Signed-off-by: Jarod Wilson <jarod@redhat.com>
---
 drivers/net/wireless/ath/wil6210/netdev.c          | 17 +----------------
 drivers/net/wireless/atmel/atmel.c                 | 13 ++++---------
 drivers/net/wireless/cisco/airo.c                  | 14 +++-----------
 drivers/net/wireless/intel/ipw2x00/ipw2100.c       |  3 ++-
 drivers/net/wireless/intel/ipw2x00/ipw2200.c       |  8 ++++++--
 drivers/net/wireless/intel/ipw2x00/libipw.h        |  1 -
 drivers/net/wireless/intel/ipw2x00/libipw_module.c |  9 ---------
 drivers/staging/wlan-ng/p80211netdev.c             | 18 +++++-------------
 8 files changed, 21 insertions(+), 62 deletions(-)

diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 61de5e9..d18372c 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -41,21 +41,6 @@ static int wil_stop(struct net_device *ndev)
 	return wil_down(wil);
 }
 
-static int wil_change_mtu(struct net_device *ndev, int new_mtu)
-{
-	struct wil6210_priv *wil = ndev_to_wil(ndev);
-
-	if (new_mtu < 68 || new_mtu > mtu_max) {
-		wil_err(wil, "invalid MTU %d\n", new_mtu);
-		return -EINVAL;
-	}
-
-	wil_dbg_misc(wil, "change MTU %d -> %d\n", ndev->mtu, new_mtu);
-	ndev->mtu = new_mtu;
-
-	return 0;
-}
-
 static int wil_do_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
 {
 	struct wil6210_priv *wil = ndev_to_wil(ndev);
@@ -69,7 +54,6 @@ static const struct net_device_ops wil_netdev_ops = {
 	.ndo_start_xmit		= wil_start_xmit,
 	.ndo_set_mac_address	= eth_mac_addr,
 	.ndo_validate_addr	= eth_validate_addr,
-	.ndo_change_mtu		= wil_change_mtu,
 	.ndo_do_ioctl		= wil_do_ioctl,
 };
 
@@ -126,6 +110,7 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
 static void wil_dev_setup(struct net_device *dev)
 {
 	ether_setup(dev);
+	dev->max_mtu = mtu_max;
 	dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT;
 }
 
diff --git a/drivers/net/wireless/atmel/atmel.c b/drivers/net/wireless/atmel/atmel.c
index bf2e9a0..eb92d5a 100644
--- a/drivers/net/wireless/atmel/atmel.c
+++ b/drivers/net/wireless/atmel/atmel.c
@@ -1295,14 +1295,6 @@ static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev)
 	return &priv->wstats;
 }
 
-static int atmel_change_mtu(struct net_device *dev, int new_mtu)
-{
-	if ((new_mtu < 68) || (new_mtu > 2312))
-		return -EINVAL;
-	dev->mtu = new_mtu;
-	return 0;
-}
-
 static int atmel_set_mac_address(struct net_device *dev, void *p)
 {
 	struct sockaddr *addr = p;
@@ -1506,7 +1498,6 @@ static const struct file_operations atmel_proc_fops = {
 static const struct net_device_ops atmel_netdev_ops = {
 	.ndo_open 		= atmel_open,
 	.ndo_stop		= atmel_close,
-	.ndo_change_mtu 	= atmel_change_mtu,
 	.ndo_set_mac_address 	= atmel_set_mac_address,
 	.ndo_start_xmit 	= start_tx,
 	.ndo_do_ioctl 		= atmel_ioctl,
@@ -1600,6 +1591,10 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
 	dev->irq = irq;
 	dev->base_addr = port;
 
+	/* MTU range: 68 - 2312 */
+	dev->min_mtu = 68;
+	dev->max_mtu = MAX_WIRELESS_BODY - ETH_FCS_LEN;
+
 	SET_NETDEV_DEV(dev, sys_dev);
 
 	if ((rc = request_irq(dev->irq, service_interrupt, IRQF_SHARED, dev->name, dev))) {
diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c
index 69b826d..4b04045 100644
--- a/drivers/net/wireless/cisco/airo.c
+++ b/drivers/net/wireless/cisco/airo.c
@@ -2329,14 +2329,6 @@ static int airo_set_mac_address(struct net_device *dev, void *p)
 	return 0;
 }
 
-static int airo_change_mtu(struct net_device *dev, int new_mtu)
-{
-	if ((new_mtu < 68) || (new_mtu > 2400))
-		return -EINVAL;
-	dev->mtu = new_mtu;
-	return 0;
-}
-
 static LIST_HEAD(airo_devices);
 
 static void add_airo_dev(struct airo_info *ai)
@@ -2656,7 +2648,6 @@ static const struct net_device_ops airo11_netdev_ops = {
 	.ndo_get_stats 		= airo_get_stats,
 	.ndo_set_mac_address	= airo_set_mac_address,
 	.ndo_do_ioctl		= airo_ioctl,
-	.ndo_change_mtu		= airo_change_mtu,
 };
 
 static void wifi_setup(struct net_device *dev)
@@ -2668,6 +2659,8 @@ static void wifi_setup(struct net_device *dev)
 	dev->type               = ARPHRD_IEEE80211;
 	dev->hard_header_len    = ETH_HLEN;
 	dev->mtu                = AIRO_DEF_MTU;
+	dev->min_mtu            = 68;
+	dev->max_mtu            = MIC_MSGLEN_MAX;
 	dev->addr_len           = ETH_ALEN;
 	dev->tx_queue_len       = 100; 
 
@@ -2754,7 +2747,6 @@ static const struct net_device_ops airo_netdev_ops = {
 	.ndo_set_rx_mode	= airo_set_multicast_list,
 	.ndo_set_mac_address	= airo_set_mac_address,
 	.ndo_do_ioctl		= airo_ioctl,
-	.ndo_change_mtu		= airo_change_mtu,
 	.ndo_validate_addr	= eth_validate_addr,
 };
 
@@ -2766,7 +2758,6 @@ static const struct net_device_ops mpi_netdev_ops = {
 	.ndo_set_rx_mode	= airo_set_multicast_list,
 	.ndo_set_mac_address	= airo_set_mac_address,
 	.ndo_do_ioctl		= airo_ioctl,
-	.ndo_change_mtu		= airo_change_mtu,
 	.ndo_validate_addr	= eth_validate_addr,
 };
 
@@ -2822,6 +2813,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
 	dev->irq = irq;
 	dev->base_addr = port;
 	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
+	dev->max_mtu = MIC_MSGLEN_MAX;
 
 	SET_NETDEV_DEV(dev, dmdev);
 
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
index bfa542c..6417609 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
@@ -6035,7 +6035,6 @@ static const struct net_device_ops ipw2100_netdev_ops = {
 	.ndo_open		= ipw2100_open,
 	.ndo_stop		= ipw2100_close,
 	.ndo_start_xmit		= libipw_xmit,
-	.ndo_change_mtu		= libipw_change_mtu,
 	.ndo_tx_timeout		= ipw2100_tx_timeout,
 	.ndo_set_mac_address	= ipw2100_set_address,
 	.ndo_validate_addr	= eth_validate_addr,
@@ -6071,6 +6070,8 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
 	dev->wireless_data = &priv->wireless_data;
 	dev->watchdog_timeo = 3 * HZ;
 	dev->irq = 0;
+	dev->min_mtu = 68;
+	dev->max_mtu = LIBIPW_DATA_LEN;
 
 	/* NOTE: We don't use the wireless_handlers hook
 	 * in dev as the system will start throwing WX requests
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
index bfd6861..ef9af8a 100644
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
@@ -11561,7 +11561,6 @@ static const struct net_device_ops ipw_prom_netdev_ops = {
 	.ndo_open 		= ipw_prom_open,
 	.ndo_stop		= ipw_prom_stop,
 	.ndo_start_xmit		= ipw_prom_hard_start_xmit,
-	.ndo_change_mtu		= libipw_change_mtu,
 	.ndo_set_mac_address 	= eth_mac_addr,
 	.ndo_validate_addr	= eth_validate_addr,
 };
@@ -11587,6 +11586,9 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
 	priv->prom_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
 	priv->prom_net_dev->netdev_ops = &ipw_prom_netdev_ops;
 
+	priv->prom_net_dev->min_mtu = 68;
+	priv->prom_net_dev->max_mtu = LIBIPW_DATA_LEN;
+
 	priv->prom_priv->ieee->iw_mode = IW_MODE_MONITOR;
 	SET_NETDEV_DEV(priv->prom_net_dev, &priv->pci_dev->dev);
 
@@ -11619,7 +11621,6 @@ static const struct net_device_ops ipw_netdev_ops = {
 	.ndo_set_rx_mode	= ipw_net_set_multicast_list,
 	.ndo_set_mac_address	= ipw_net_set_mac_address,
 	.ndo_start_xmit		= libipw_xmit,
-	.ndo_change_mtu		= libipw_change_mtu,
 	.ndo_validate_addr	= eth_validate_addr,
 };
 
@@ -11729,6 +11730,9 @@ static int ipw_pci_probe(struct pci_dev *pdev,
 	net_dev->wireless_handlers = &ipw_wx_handler_def;
 	net_dev->ethtool_ops = &ipw_ethtool_ops;
 
+	net_dev->min_mtu = 68;
+	net_dev->max_mtu = LIBIPW_DATA_LEN;
+
 	err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group);
 	if (err) {
 		IPW_ERROR("failed to create sysfs device attributes\n");
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw.h b/drivers/net/wireless/intel/ipw2x00/libipw.h
index b057161..b513551 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw.h
+++ b/drivers/net/wireless/intel/ipw2x00/libipw.h
@@ -948,7 +948,6 @@ static inline int libipw_is_cck_rate(u8 rate)
 /* libipw.c */
 void free_libipw(struct net_device *dev, int monitor);
 struct net_device *alloc_libipw(int sizeof_priv, int monitor);
-int libipw_change_mtu(struct net_device *dev, int new_mtu);
 
 void libipw_networks_age(struct libipw_device *ieee, unsigned long age_secs);
 
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c
index 60f2874..2332075 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_module.c
@@ -118,15 +118,6 @@ static void libipw_networks_initialize(struct libipw_device *ieee)
 			      &ieee->network_free_list);
 }
 
-int libipw_change_mtu(struct net_device *dev, int new_mtu)
-{
-	if ((new_mtu < 68) || (new_mtu > LIBIPW_DATA_LEN))
-		return -EINVAL;
-	dev->mtu = new_mtu;
-	return 0;
-}
-EXPORT_SYMBOL(libipw_change_mtu);
-
 struct net_device *alloc_libipw(int sizeof_priv, int monitor)
 {
 	struct libipw_device *ieee;
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index 825a63a..4762d38 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -669,18 +669,6 @@ static int p80211knetdev_set_mac_address(struct net_device *dev, void *addr)
 	return result;
 }
 
-static int wlan_change_mtu(struct net_device *dev, int new_mtu)
-{
-	/* 2312 is max 802.11 payload, 20 is overhead, (ether + llc +snap)
-	   and another 8 for wep. */
-	if ((new_mtu < 68) || (new_mtu > (2312 - 20 - 8)))
-		return -EINVAL;
-
-	dev->mtu = new_mtu;
-
-	return 0;
-}
-
 static const struct net_device_ops p80211_netdev_ops = {
 	.ndo_init = p80211knetdev_init,
 	.ndo_open = p80211knetdev_open,
@@ -690,7 +678,6 @@ static const struct net_device_ops p80211_netdev_ops = {
 	.ndo_do_ioctl = p80211knetdev_do_ioctl,
 	.ndo_set_mac_address = p80211knetdev_set_mac_address,
 	.ndo_tx_timeout = p80211knetdev_tx_timeout,
-	.ndo_change_mtu = wlan_change_mtu,
 	.ndo_validate_addr = eth_validate_addr,
 };
 
@@ -756,6 +743,11 @@ int wlan_setup(struct wlandevice *wlandev, struct device *physdev)
 		wdev->wiphy = wiphy;
 		wdev->iftype = NL80211_IFTYPE_STATION;
 		netdev->ieee80211_ptr = wdev;
+		netdev->min_mtu = 68;
+		/* 2312 is max 802.11 payload, 20 is overhead,
+		 * (ether + llc + snap) and another 8 for wep.
+		 */
+		netdev->max_mtu = (2312 - 20 - 8);
 
 		netif_stop_queue(netdev);
 		netif_carrier_off(netdev);
-- 
2.10.0

^ permalink raw reply related

* Re: [PATCH] crypto: ccm - avoid scatterlist for MAC encryption
From: Herbert Xu @ 2016-10-19  3:31 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Andy Lutomirski, Johannes Berg, Sergey Senozhatsky,
	<netdev@vger.kernel.org>, David S. Miller,
	<linux-wireless@vger.kernel.org>,
	linux-kernel@vger.kernel.org, Jouni Malinen
In-Reply-To: <CAKv+Gu-25OvTSbyE06Ln8N+HsqNyV1T6oOudK2tyAAOmmXXqgA@mail.gmail.com>

On Mon, Oct 17, 2016 at 06:21:14PM +0100, Ard Biesheuvel wrote:
>
> Annoyingly, all this complication with scatterlists etc is for doing
> asynchronous crypto via DMA capable crypto accelerators, and the
> networking code (ipsec as well as mac80211, afaik) only allow
> synchronous in the first place, given that they execute in softirq
> context.

I'm still thinking about the issue (in particular, whether we
should continue to rely on the request context being SG-capable
or allow it to be on the stack for AEAD).

But IPsec definitely supports async crypto.  In fact it was the
very first user of async crypto.

mac80211 on the other hand is currently sync-only.

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* [PATCH] cfg80211: allow vendor commands to be sent to nan interface
From: Luca Coelho @ 2016-10-19  4:47 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Andrei Otcheretianski, Luca Coelho

From: Andrei Otcheretianski <andrei.otcheretianski@intel.com>

Allow vendor commands that require WIPHY_VENDOR_CMD_NEED_RUNNING flag, to
be sent to NAN interface.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 net/wireless/nl80211.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e48b9c3..fcf5b4f 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -11258,7 +11258,8 @@ static int nl80211_vendor_cmd(struct sk_buff *skb, struct genl_info *info)
 				if (wdev->netdev &&
 				    !netif_running(wdev->netdev))
 					return -ENETDOWN;
-				if (!wdev->netdev && !wdev->p2p_started)
+				if (!wdev->netdev && !wdev->p2p_started &&
+				    !wdev->nan_started)
 					return -ENETDOWN;
 			}
 
-- 
2.9.3

^ permalink raw reply related

* Re: [PATCH 0/7] patches for mac80211/cfg80211 2016-10-18
From: Johannes Berg @ 2016-10-19 10:17 UTC (permalink / raw)
  To: Luca Coelho; +Cc: linux-wireless, Luca Coelho
In-Reply-To: <20161018201213.18873-1-luca@coelho.fi>

On Tue, 2016-10-18 at 23:12 +0300, Luca Coelho wrote:
> From: Luca Coelho <luciano.coelho@intel.com>
> 
> Hi Johannes,
> 
> Here are a few patches for mac80211/cfg80211 from our internal tree.
> You're probably familiar with most of them, I'm just adding a cover
> letter to make it easier for you to reply "Applied all"
> (hopefully).:)

Heh, ok, done; all are in mac80211-next, I didn't think they were
important for mac80211. My NULL deref fix is debatable, but the
hardware that supports this isn't shipping yet, and will never work
with this kernel due to firmware release/compatibility anyway.

Also the NAN patch you sent separately.

johannes

^ permalink raw reply

* Re: BCM43602 firmware reports multiple BRCMF_E_DEAUTH
From: Rafał Miłecki @ 2016-10-19 12:34 UTC (permalink / raw)
  To: linux-wireless@vger.kernel.org, brcm80211 development
In-Reply-To: <f97678dc-2869-1b6a-33a3-f829cc30918a@gmail.com>

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

On 10/04/2016 08:15 PM, Rafał Miłecki wrote:
> # My smartphone remains in the same place (1 m from the AP) but there is some
> # connection/A-MPDU problem.
> Tue Oct  4 17:22:22 2016 kern.debug kernel: [  247.509120] brcmfmac: CONSOLE: 026970.308 ampdu_dbg: wl0.0 scb:0035ee78 tid:0
> Tue Oct  4 17:22:22 2016 kern.debug kernel: [  247.509250] brcmfmac: CONSOLE: 026970.308 ampdu_dbg: wl0.0 dead_cnt 2 tx_in_transit 1 psm_mux 0xfff0 aqmqmap 0x0x101 aqmfifo_status 0x0x4000 fifordy 0x0 cpbusy 0x0
> Tue Oct  4 17:22:22 2016 kern.debug kernel: [  247.509304] brcmfmac: CONSOLE: 026970.308 ampdu_dbg: ifsstat 0xaf nav_stat 0x0 txop 110486
> Tue Oct  4 17:22:22 2016 kern.debug kernel: [  247.509346] brcmfmac: CONSOLE: 026970.308 ampdu_dbg: pktpend: 0 0 0 0 0 ap 1
> Tue Oct  4 17:22:22 2016 kern.debug kernel: [  247.509411] brcmfmac: CONSOLE: 026970.308 ampdu_dbg: txall 4 txbcn 0 txrts 0 rxcts 0 rsptmout 0 rxstrt 0
> Tue Oct  4 17:22:22 2016 kern.debug kernel: [  247.509477] brcmfmac: CONSOLE: 026970.308 ampdu_dbg: cwcur0-3 f f 7 3 bslots cur/0-3 4 0 0 0 0 ifs_boff 0
> Tue Oct  4 17:22:22 2016 kern.debug kernel: [  247.509527] brcmfmac: CONSOLE: 026970.308 ampdu_dbg: again1 ifsstat 0xaf nav_stat 0x0
> Tue Oct  4 17:22:22 2016 kern.debug kernel: [  247.509576] brcmfmac: CONSOLE: 026970.308 ampdu_dbg: again2 ifsstat 0xaf nav_stat 0x0
> Tue Oct  4 17:22:22 2016 kern.debug kernel: [  247.509665] brcmfmac: CONSOLE: 026970.308 wl0: wlc_ampdu_watchdog: cleaning up ini tid 0 due to no progress for 2 secs tx_in_transit 1
> Tue Oct  4 17:22:22 2016 kern.debug kernel: [  247.509726] brcmfmac: CONSOLE: 026970.308 wl0: wlc_ampdu_tx_send_delba: tid 0 initiator 1 reason 39
> Tue Oct  4 17:22:41 2016 kern.debug kernel: [  266.456860] brcmfmac: CONSOLE: 026990.068 wl0.0: wlc_send_bar: seq 0x7c tid 0
> Tue Oct  4 17:22:43 2016 kern.debug kernel: [  268.178234] brcmfmac: CONSOLE: 026991.783 pktid is NULL
>
> # After recovering from A-MPDU thing firmware sends BRCMF_E_DEAUTH and
> # BRCMF_E_DISASSOC_IND events.
> # My smartphone never receives deauth/disassoc and it believes it's still
> # connected to the AP.
> Tue Oct  4 17:23:24 2016 kern.debug kernel: [  309.275305] brcmfmac: brcmf_notify_connect_status_ap event 5, reason 4
> Tue Oct  4 17:23:24 2016 daemon.info hostapd: wlan1: STA 78:d6:f0:9b:ba:bc IEEE 802.11: disassociated
> Tue Oct  4 17:23:24 2016 kern.debug kernel: [  309.275354] brcmfmac: brcmf_notify_connect_status_ap event 12, reason 8
> Tue Oct  4 17:23:24 2016 daemon.info hostapd: wlan1: STA 78:d6:f0:9b:ba:bc IEEE 802.11: disassociated
> Tue Oct  4 17:23:24 2016 kern.debug kernel: [  309.275865] brcmfmac: brcmf_cfg80211_del_key key index (0)
> Tue Oct  4 17:23:24 2016 kern.debug kernel: [  309.276177] brcmfmac: brcmf_cfg80211_del_key key index (0)
> Tue Oct  4 17:23:24 2016 kern.debug kernel: [  309.276188] brcmfmac: brcmf_cfg80211_del_key Ignore clearing of (never configured) key
>
> # My smartphone starts sending packets. It seems brcmfmac refuses them due to
> # STA not being connected and for each packet it reports BRCMF_E_DEAUTH to the
> # driver.
> Tue Oct  4 17:23:58 2016 kern.debug kernel: [  343.000406] brcmfmac: brcmf_notify_connect_status_ap event 5, reason 7
> Tue Oct  4 17:23:58 2016 daemon.info hostapd: wlan1: STA 78:d6:f0:9b:ba:bc IEEE 802.11: disassociated
> Tue Oct  4 17:23:58 2016 kern.debug kernel: [  343.001227] brcmfmac: brcmf_notify_connect_status_ap event 5, reason 7
> Tue Oct  4 17:23:58 2016 daemon.info hostapd: wlan1: STA 78:d6:f0:9b:ba:bc IEEE 802.11: disassociated
> Tue Oct  4 17:23:58 2016 kern.debug kernel: [  343.001894] brcmfmac: brcmf_notify_connect_status_ap event 5, reason 7
> Tue Oct  4 17:23:58 2016 daemon.info hostapd: wlan1: STA 78:d6:f0:9b:ba:bc IEEE 802.11: disassociated
> Tue Oct  4 17:23:58 2016 kern.debug kernel: [  343.002594] brcmfmac: brcmf_notify_connect_status_ap event 5, reason 7
> Tue Oct  4 17:23:58 2016 daemon.info hostapd: wlan1: STA 78:d6:f0:9b:ba:bc IEEE 802.11: disassociated
> Tue Oct  4 17:23:58 2016 kern.debug kernel: [  343.003741] brcmfmac: brcmf_notify_connect_status_ap event 5, reason 7
> Tue Oct  4 17:23:58 2016 daemon.info hostapd: wlan1: STA 78:d6:f0:9b:ba:bc IEEE 802.11: disassociated
> Tue Oct  4 17:23:58 2016 kern.debug kernel: [  343.004096] brcmfmac: brcmf_notify_connect_status_ap event 5, reason 7
> Tue Oct  4 17:23:58 2016 daemon.info hostapd: wlan1: STA 78:d6:f0:9b:ba:bc IEEE 802.11: disassociated
> Tue Oct  4 17:23:58 2016 kern.debug kernel: [  343.004490] brcmfmac: brcmf_notify_connect_status_ap event 5, reason 7
> Tue Oct  4 17:23:58 2016 daemon.info hostapd: wlan1: STA 78:d6:f0:9b:ba:bc IEEE 802.11: disassociated
> Tue Oct  4 17:23:58 2016 kern.debug kernel: [  343.004936] brcmfmac: brcmf_notify_connect_status_ap event 5, reason 7
> Tue Oct  4 17:23:58 2016 daemon.info hostapd: wlan1: STA 78:d6:f0:9b:ba:bc IEEE 802.11: disassociated

I just got 400+ messages like this:
wlan1: STA 84:38:38:e4:b5:ea IEEE 802.11: disassociated
this time I was lucky enough to have monitor mode running on some independent
notebook and I got it recorded.

I'm attaching pcapng (Wireshark dump) file. You can see a lot of
Deauthentication frames flying both ways with a reason code 0x0006 (Class 2
frame received from nonauthenticated STA).

I think this reason code seems to match my suspicions: STA didn't realize it was
disconnected and it kept sending packets. Firmware reacted sending Deauth frames

[-- Attachment #2: deauth.tar.bz2 --]
[-- Type: application/x-bzip, Size: 5424 bytes --]

^ permalink raw reply

* Re: [PATCH net-next 2/6] net: use core MTU range checking in wireless drivers
From: Jarod Wilson @ 2016-10-19 14:27 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-kernel, netdev, linux-wireless, Maya Erez, Simon Kelley,
	Stanislav Yakovlev
In-Reply-To: <1476862713.5927.0.camel@sipsolutions.net>

On Wed, Oct 19, 2016 at 09:38:33AM +0200, Johannes Berg wrote:
> On Tue, 2016-10-18 at 22:33 -0400, Jarod Wilson wrote:
> > - set max_mtu in wil6210 driver
> > - set max_mtu in atmel driver
> > - set min/max_mtu in cisco airo driver, remove airo_change_mtu
> > - set min/max_mtu in ipw2100/ipw2200 drivers, remove
> > libipw_change_mtu
> > - set min/max_mtu in p80211netdev, remove wlan_change_mtu
> 
> I guess we should do the same in net/mac80211/iface.c?

Yeah. I thought I'd located all places this needed to happen, but
obviously not. I'll get this added and do another sweep for others I might
have missed.

-- 
Jarod Wilson
jarod@redhat.com

^ permalink raw reply

* Re: [PATCH net-next 2/6] net: use core MTU range checking in wireless drivers
From: Johannes Berg @ 2016-10-19 14:28 UTC (permalink / raw)
  To: Jarod Wilson
  Cc: linux-kernel, netdev, linux-wireless, Maya Erez, Simon Kelley,
	Stanislav Yakovlev
In-Reply-To: <20161019142706.GE18569@redhat.com>


> > I guess we should do the same in net/mac80211/iface.c?
> 
> Yeah. I thought I'd located all places this needed to happen, but
> obviously not. I'll get this added and do another sweep for others I
> might have missed.

No worries. I can also do it if you prefer, just wanted to ask :)

johannes

^ permalink raw reply

* [PATCH 6/7] iwlwifi: pcie: fix SPLC structure parsing
From: Luca Coelho @ 2016-10-19  7:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, Luca Coelho
In-Reply-To: <20161019072726.22018-1-luca@coelho.fi>

From: Luca Coelho <luciano.coelho@intel.com>

The SPLC data parsing is too restrictive and was not trying find the
correct element for WiFi.  This causes problems with some BIOSes where
the SPLC method exists, but doesn't have a WiFi entry on the first
element of the list.  The domain type values are also incorrect
according to the specification.

Fix this by complying with the actual specification.

Additionally, replace all occurrences of SPLX to SPLC, since SPLX is
only a structure internal to the ACPI tables, and may not even exist.

Fixes: bcb079a14d75 ("iwlwifi: pcie: retrieve and parse ACPI power limitations")
Reported-by: Chris Rorvick <chris@rorvick.com>
Tested-by: Paul Bolle <pebolle@tiscali.nl>
Tested-by: Chris Rorvick <chris@rorvick.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 79 ++++++++++++++++-----------
 1 file changed, 48 insertions(+), 31 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index 001be40..2f8134b 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -541,48 +541,64 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
 MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
 
 #ifdef CONFIG_ACPI
-#define SPL_METHOD		"SPLC"
-#define SPL_DOMAINTYPE_MODULE	BIT(0)
-#define SPL_DOMAINTYPE_WIFI	BIT(1)
-#define SPL_DOMAINTYPE_WIGIG	BIT(2)
-#define SPL_DOMAINTYPE_RFEM	BIT(3)
+#define ACPI_SPLC_METHOD	"SPLC"
+#define ACPI_SPLC_DOMAIN_WIFI	(0x07)
 
-static u64 splx_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splx)
+static u64 splc_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splc)
 {
-	union acpi_object *limits, *domain_type, *power_limit;
-
-	if (splx->type != ACPI_TYPE_PACKAGE ||
-	    splx->package.count != 2 ||
-	    splx->package.elements[0].type != ACPI_TYPE_INTEGER ||
-	    splx->package.elements[0].integer.value != 0) {
-		IWL_ERR(trans, "Unsupported splx structure\n");
+	union acpi_object *data_pkg, *dflt_pwr_limit;
+	int i;
+
+	/* We need at least two elements, one for the revision and one
+	 * for the data itself.  Also check that the revision is
+	 * supported (currently only revision 0).
+	*/
+	if (splc->type != ACPI_TYPE_PACKAGE ||
+	    splc->package.count < 2 ||
+	    splc->package.elements[0].type != ACPI_TYPE_INTEGER ||
+	    splc->package.elements[0].integer.value != 0) {
+		IWL_DEBUG_INFO(trans,
+			       "Unsupported structure returned by the SPLC method.  Ignoring.\n");
 		return 0;
 	}
 
-	limits = &splx->package.elements[1];
-	if (limits->type != ACPI_TYPE_PACKAGE ||
-	    limits->package.count < 2 ||
-	    limits->package.elements[0].type != ACPI_TYPE_INTEGER ||
-	    limits->package.elements[1].type != ACPI_TYPE_INTEGER) {
-		IWL_ERR(trans, "Invalid limits element\n");
-		return 0;
+	/* loop through all the packages to find the one for WiFi */
+	for (i = 1; i < splc->package.count; i++) {
+		union acpi_object *domain;
+
+		data_pkg = &splc->package.elements[i];
+
+		/* Skip anything that is not a package with the right
+		 * amount of elements (i.e. at least 2 integers).
+		 */
+		if (data_pkg->type != ACPI_TYPE_PACKAGE ||
+		    data_pkg->package.count < 2 ||
+		    data_pkg->package.elements[0].type != ACPI_TYPE_INTEGER ||
+		    data_pkg->package.elements[1].type != ACPI_TYPE_INTEGER)
+			continue;
+
+		domain = &data_pkg->package.elements[0];
+		if (domain->integer.value == ACPI_SPLC_DOMAIN_WIFI)
+			break;
+
+		data_pkg = NULL;
 	}
 
-	domain_type = &limits->package.elements[0];
-	power_limit = &limits->package.elements[1];
-	if (!(domain_type->integer.value & SPL_DOMAINTYPE_WIFI)) {
-		IWL_DEBUG_INFO(trans, "WiFi power is not limited\n");
+	if (!data_pkg) {
+		IWL_DEBUG_INFO(trans,
+			       "No element for the WiFi domain returned by the SPLC method.\n");
 		return 0;
 	}
 
-	return power_limit->integer.value;
+	dflt_pwr_limit = &data_pkg->package.elements[1];
+	return dflt_pwr_limit->integer.value;
 }
 
 static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev)
 {
 	acpi_handle pxsx_handle;
 	acpi_handle handle;
-	struct acpi_buffer splx = {ACPI_ALLOCATE_BUFFER, NULL};
+	struct acpi_buffer splc = {ACPI_ALLOCATE_BUFFER, NULL};
 	acpi_status status;
 
 	pxsx_handle = ACPI_HANDLE(&pdev->dev);
@@ -593,23 +609,24 @@ static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev)
 	}
 
 	/* Get the method's handle */
-	status = acpi_get_handle(pxsx_handle, (acpi_string)SPL_METHOD, &handle);
+	status = acpi_get_handle(pxsx_handle, (acpi_string)ACPI_SPLC_METHOD,
+				 &handle);
 	if (ACPI_FAILURE(status)) {
-		IWL_DEBUG_INFO(trans, "SPL method not found\n");
+		IWL_DEBUG_INFO(trans, "SPLC method not found\n");
 		return;
 	}
 
 	/* Call SPLC with no arguments */
-	status = acpi_evaluate_object(handle, NULL, NULL, &splx);
+	status = acpi_evaluate_object(handle, NULL, NULL, &splc);
 	if (ACPI_FAILURE(status)) {
 		IWL_ERR(trans, "SPLC invocation failed (0x%x)\n", status);
 		return;
 	}
 
-	trans->dflt_pwr_limit = splx_get_pwr_limit(trans, splx.pointer);
+	trans->dflt_pwr_limit = splc_get_pwr_limit(trans, splc.pointer);
 	IWL_DEBUG_INFO(trans, "Default power limit set to %lld\n",
 		       trans->dflt_pwr_limit);
-	kfree(splx.pointer);
+	kfree(splc.pointer);
 }
 
 #else /* CONFIG_ACPI */
-- 
2.9.3

^ permalink raw reply related

* [PATCH 7/7] iwlwifi: mvm: fix netdetect starting/stopping for unified images
From: Luca Coelho @ 2016-10-19  7:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, Luca Coelho
In-Reply-To: <20161019072726.22018-1-luca@coelho.fi>

From: Luca Coelho <luciano.coelho@intel.com>

With unified images, we need to make sure the net-detect scan is
stopped after resuming, since we don't restart the FW.  Also, we need
to make sure we check if there are enough scan slots available to run
it, as we do with other scans.

Fixes: commit 23ae61282b88 ("iwlwifi: mvm: Do not switch to D3 image on suspend")
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/d3.c   | 19 +++++++++++++++
 drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 33 ++++++++++++++++++++++-----
 2 files changed, 46 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 03a8fc5..b88e204 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -1087,6 +1087,15 @@ iwl_mvm_netdetect_config(struct iwl_mvm *mvm,
 		ret = iwl_mvm_switch_to_d3(mvm);
 		if (ret)
 			return ret;
+	} else {
+		/* In theory, we wouldn't have to stop a running sched
+		 * scan in order to start another one (for
+		 * net-detect).  But in practice this doesn't seem to
+		 * work properly, so stop any running sched_scan now.
+		 */
+		ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true);
+		if (ret)
+			return ret;
 	}
 
 	/* rfkill release can be either for wowlan or netdetect */
@@ -2091,6 +2100,16 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
 	iwl_mvm_update_changed_regdom(mvm);
 
 	if (mvm->net_detect) {
+		/* If this is a non-unified image, we restart the FW,
+		 * so no need to stop the netdetect scan.  If that
+		 * fails, continue and try to get the wake-up reasons,
+		 * but trigger a HW restart by keeping a failure code
+		 * in ret.
+		 */
+		if (unified_image)
+			ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_NETDETECT,
+						false);
+
 		iwl_mvm_query_netdetect_reasons(mvm, vif);
 		/* has unlocked the mutex, so skip that */
 		goto out;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index f279fdd..fa97432 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -1199,6 +1199,9 @@ static int iwl_mvm_num_scans(struct iwl_mvm *mvm)
 
 static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type)
 {
+	bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
+					 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
+
 	/* This looks a bit arbitrary, but the idea is that if we run
 	 * out of possible simultaneous scans and the userspace is
 	 * trying to run a scan type that is already running, we
@@ -1225,12 +1228,30 @@ static int iwl_mvm_check_running_scans(struct iwl_mvm *mvm, int type)
 			return -EBUSY;
 		return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);
 	case IWL_MVM_SCAN_NETDETECT:
-		/* No need to stop anything for net-detect since the
-		 * firmware is restarted anyway.  This way, any sched
-		 * scans that were running will be restarted when we
-		 * resume.
-		*/
-		return 0;
+		/* For non-unified images, there's no need to stop
+		 * anything for net-detect since the firmware is
+		 * restarted anyway.  This way, any sched scans that
+		 * were running will be restarted when we resume.
+		 */
+		if (!unified_image)
+			return 0;
+
+		/* If this is a unified image and we ran out of scans,
+		 * we need to stop something.  Prefer stopping regular
+		 * scans, because the results are useless at this
+		 * point, and we should be able to keep running
+		 * another scheduled scan while suspended.
+		 */
+		if (mvm->scan_status & IWL_MVM_SCAN_REGULAR_MASK)
+			return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR,
+						 true);
+		if (mvm->scan_status & IWL_MVM_SCAN_SCHED_MASK)
+			return iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED,
+						 true);
+
+		/* fall through, something is wrong if no scan was
+		 * running but we ran out of scans.
+		 */
 	default:
 		WARN_ON(1);
 		break;
-- 
2.9.3

^ permalink raw reply related

* [PATCH 4/7] iwlwifi: mvm: comply with fw_restart mod param on suspend
From: Luca Coelho @ 2016-10-19  7:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, Haim Dreyfuss, Luca Coelho
In-Reply-To: <20161019072726.22018-1-luca@coelho.fi>

From: Haim Dreyfuss <haim.dreyfuss@intel.com>

If the suspend flow fails, we restart the hardware to go back to
the D0 image (with non-unified images), but we don't comply with
the fw_restart module parameter.  If something goes wrong when
starting the D3 image, we may want to debug it, so we should
comply with the fw_restart flag to avoid clearing everything up
and losing the firmware state when the error occurred.

Signed-off-by: Haim Dreyfuss <haim.dreyfuss@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 0e17cb2..03a8fc5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -1254,7 +1254,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
  out:
 	if (ret < 0) {
 		iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
-		ieee80211_restart_hw(mvm->hw);
+		if (mvm->restart_fw > 0) {
+			mvm->restart_fw--;
+			ieee80211_restart_hw(mvm->hw);
+		}
 		iwl_mvm_free_nd(mvm);
 	}
  out_noreset:
-- 
2.9.3

^ permalink raw reply related

* [PATCH 2/7] iwlwifi: mvm: use ssize_t for len in iwl_debugfs_mem_read()
From: Luca Coelho @ 2016-10-19  7:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, Luca Coelho
In-Reply-To: <20161019072726.22018-1-luca@coelho.fi>

From: Luca Coelho <luciano.coelho@intel.com>

In iwl_dbgfs_mem_read(), the len variable may become negative and is
compared to < 0 (an error case).  Comparing size_t (which is unsigned)
to < 0 causes a warning on certain platforms (like i386):

drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c:1561:5-8: WARNING: Unsigned expression compared with zero: len < 0

To prevent that, use ssize_t for len instead.

Fixes: commit 2b55f43f8e47 ("iwlwifi: mvm: Add mem debugfs entry")
Reported-by: kbuild test robot <fengguang.wu@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
index 539d718..06805a6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
@@ -1529,8 +1529,8 @@ static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf,
 		.data = { &cmd, },
 		.len = { sizeof(cmd) },
 	};
-	size_t delta, len;
-	ssize_t ret;
+	size_t delta;
+	ssize_t ret, len;
 
 	hcmd.id = iwl_cmd_id(*ppos >> 24 ? UMAC_RD_WR : LMAC_RD_WR,
 			     DEBUG_GROUP, 0);
-- 
2.9.3

^ permalink raw reply related

* [PATCH 0/7] iwlwifi: updates intended for v4.9 2016-10-19
From: Luca Coelho @ 2016-10-19  7:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, Luca Coelho

From: Luca Coelho <luciano.coelho@intel.com>

Hi,

Here are a few fixes that I'm planning to send for v4.9.  Nothing
major, here's what they are about:

* some fixes for suspend/resume with unified FW images;
* a fix for a false-positive lockdep report;
* a fix for multi-queue that caused an unnecessary 1 second latency;
* a fix for an ACPI parsing bug that caused a misleading error
  message;

I'll leave this in my pending branch for a while to get kbuild bot
reports and then I'll send a pull-request.

Please review.

Cheers,
Luca.


Haim Dreyfuss (1):
  iwlwifi: mvm: comply with fw_restart mod param on suspend

Johannes Berg (1):
  iwlwifi: pcie: mark command queue lock with separate lockdep class

Luca Coelho (4):
  iwlwifi: mvm: use ssize_t for len in iwl_debugfs_mem_read()
  iwlwifi: mvm: fix d3_test with unified D0/D3 images
  iwlwifi: pcie: fix SPLC structure parsing
  iwlwifi: mvm: fix netdetect starting/stopping for unified images

Sara Sharon (1):
  iwlwifi: mvm: wake the wait queue when the RX sync counter is zero

 drivers/net/wireless/intel/iwlwifi/mvm/d3.c       | 49 ++++++++++----
 drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c  |  4 +-
 drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c |  3 +-
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h      |  1 +
 drivers/net/wireless/intel/iwlwifi/mvm/ops.c      |  1 +
 drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c     |  3 +-
 drivers/net/wireless/intel/iwlwifi/mvm/scan.c     | 33 ++++++++--
 drivers/net/wireless/intel/iwlwifi/pcie/drv.c     | 79 ++++++++++++++---------
 drivers/net/wireless/intel/iwlwifi/pcie/tx.c      |  8 +++
 9 files changed, 128 insertions(+), 53 deletions(-)

-- 
2.9.3

^ permalink raw reply

* [PATCH 1/7] iwlwifi: pcie: mark command queue lock with separate lockdep class
From: Luca Coelho @ 2016-10-19  7:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, Johannes Berg, Luca Coelho
In-Reply-To: <20161019072726.22018-1-luca@coelho.fi>

From: Johannes Berg <johannes.berg@intel.com>

Emmanuel reports that when CMD_WANT_ASYNC_CALLBACK is used by mvm,
the callback will be called with the command queue lock held, and
mvm will try to stop all (other) TX queues, which acquires their
locks - this caused a false lockdep recursive locking report.

Suppress this report by marking the command queue lock with a new,
separate, lock class so lockdep can tell the difference between
the two types of queues.

Fixes: 156f92f2b471 ("iwlwifi: block the queues when we send ADD_STA for uAPSD")
Reported-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/pcie/tx.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
index e9a278b..5f840f1 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
@@ -592,6 +592,7 @@ error:
 static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
 			      int slots_num, u32 txq_id)
 {
+	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 	int ret;
 
 	txq->need_update = false;
@@ -606,6 +607,13 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
 		return ret;
 
 	spin_lock_init(&txq->lock);
+
+	if (txq_id == trans_pcie->cmd_queue) {
+		static struct lock_class_key iwl_pcie_cmd_queue_lock_class;
+
+		lockdep_set_class(&txq->lock, &iwl_pcie_cmd_queue_lock_class);
+	}
+
 	__skb_queue_head_init(&txq->overflow_q);
 
 	/*
-- 
2.9.3

^ permalink raw reply related

* [PATCH 5/7] iwlwifi: mvm: wake the wait queue when the RX sync counter is zero
From: Luca Coelho @ 2016-10-19  7:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, Sara Sharon, Luca Coelho
In-Reply-To: <20161019072726.22018-1-luca@coelho.fi>

From: Sara Sharon <sara.sharon@intel.com>

When we sync the RX queues the driver waits to receive echo
notification on all the RX queues.
The wait queue is set with timeout until all queues have received
the notification.
However, iwl_mvm_rx_queue_notif() never woke up the wait queue,
with the result of the counter value being checked only when the
timeout expired.
This may cause a latency of up to 1 second.

Fixes: 0636b938214c ("iwlwifi: mvm: implement driver RX queues sync command")
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 +--
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h      | 1 +
 drivers/net/wireless/intel/iwlwifi/mvm/ops.c      | 1 +
 drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c     | 3 ++-
 4 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 318efd8..1db1dc1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -4121,7 +4121,6 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
 				     struct iwl_mvm_internal_rxq_notif *notif,
 				     u32 size)
 {
-	DECLARE_WAIT_QUEUE_HEAD_ONSTACK(notif_waitq);
 	u32 qmask = BIT(mvm->trans->num_rx_queues) - 1;
 	int ret;
 
@@ -4143,7 +4142,7 @@ void iwl_mvm_sync_rx_queues_internal(struct iwl_mvm *mvm,
 	}
 
 	if (notif->sync)
-		ret = wait_event_timeout(notif_waitq,
+		ret = wait_event_timeout(mvm->rx_sync_waitq,
 					 atomic_read(&mvm->queue_sync_counter) == 0,
 					 HZ);
 	WARN_ON_ONCE(!ret);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index d17cbf6..c60703e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -937,6 +937,7 @@ struct iwl_mvm {
 	/* sync d0i3_tx queue and IWL_MVM_STATUS_IN_D0I3 status flag */
 	spinlock_t d0i3_tx_lock;
 	wait_queue_head_t d0i3_exit_waitq;
+	wait_queue_head_t rx_sync_waitq;
 
 	/* BT-Coex */
 	struct iwl_bt_coex_profile_notif last_bt_notif;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 05fe6dd..4d35deb 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -619,6 +619,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 	spin_lock_init(&mvm->refs_lock);
 	skb_queue_head_init(&mvm->d0i3_tx);
 	init_waitqueue_head(&mvm->d0i3_exit_waitq);
+	init_waitqueue_head(&mvm->rx_sync_waitq);
 
 	atomic_set(&mvm->queue_sync_counter, 0);
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index a57c6ef..6c802ce 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -547,7 +547,8 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
 				  "Received expired RX queue sync message\n");
 			return;
 		}
-		atomic_dec(&mvm->queue_sync_counter);
+		if (!atomic_dec_return(&mvm->queue_sync_counter))
+			wake_up(&mvm->rx_sync_waitq);
 	}
 
 	switch (internal_notif->type) {
-- 
2.9.3

^ permalink raw reply related

* [PATCH 3/7] iwlwifi: mvm: fix d3_test with unified D0/D3 images
From: Luca Coelho @ 2016-10-19  7:27 UTC (permalink / raw)
  To: linux-wireless; +Cc: kvalo, Luca Coelho
In-Reply-To: <20161019072726.22018-1-luca@coelho.fi>

From: Luca Coelho <luciano.coelho@intel.com>

When a unified D0/D3 image is used, we don't restart the FW in the
D0->D3->D0 transitions.  Therefore, the d3_test functionality should
not call ieee8021_restart_hw() when the resuming either.

Fixes: commit 23ae61282b88 ("iwlwifi: mvm: Do not switch to D3 image on suspend")
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
index 4fdc3da..0e17cb2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
@@ -2271,7 +2271,8 @@ static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac,
 static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
 {
 	struct iwl_mvm *mvm = inode->i_private;
-	int remaining_time = 10;
+	bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
+					 IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
 
 	mvm->d3_test_active = false;
 
@@ -2282,17 +2283,21 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
 	mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
 
 	iwl_abort_notification_waits(&mvm->notif_wait);
-	ieee80211_restart_hw(mvm->hw);
+	if (!unified_image) {
+		int remaining_time = 10;
 
-	/* wait for restart and disconnect all interfaces */
-	while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
-	       remaining_time > 0) {
-		remaining_time--;
-		msleep(1000);
-	}
+		ieee80211_restart_hw(mvm->hw);
+
+		/* wait for restart and disconnect all interfaces */
+		while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
+		       remaining_time > 0) {
+			remaining_time--;
+			msleep(1000);
+		}
 
-	if (remaining_time == 0)
-		IWL_ERR(mvm, "Timed out waiting for HW restart to finish!\n");
+		if (remaining_time == 0)
+			IWL_ERR(mvm, "Timed out waiting for HW restart!\n");
+	}
 
 	ieee80211_iterate_active_interfaces_atomic(
 		mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
-- 
2.9.3

^ permalink raw reply related

* [char-misc-next 1/5] mei: bus: add  module_mei_cl_driver helper macro
From: Tomas Winkler @ 2016-10-19 13:33 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Aloisio Almeida Jr, Samuel Ortiz,
	Wim Van Sebroeck, Guenter Roeck
  Cc: Alexander Usyskin, linux-kernel, linux-wireless, linux-watchdog,
	Tomas Winkler
In-Reply-To: <1476884011-20645-1-git-send-email-tomas.winkler@intel.com>

Add module_mei_cl_driver helper macro for eliminating the boilerplate
code from mei_cl drivers registration. The macro is intended for
drivers which in their init/exit sections does only register/unregister
of a mei_cl driver.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 include/linux/mei_cl_bus.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h
index e746919530f5..e6fbd98ea90e 100644
--- a/include/linux/mei_cl_bus.h
+++ b/include/linux/mei_cl_bus.h
@@ -74,6 +74,19 @@ int __mei_cldev_driver_register(struct mei_cl_driver *cldrv,
 
 void mei_cldev_driver_unregister(struct mei_cl_driver *cldrv);
 
+/**
+ * module_mei_cl_driver - Helper macro for registering mei cl driver
+ *
+ * @__mei_cldrv mei_cl_driver structure
+ *
+ *  Helper macro for mei cl drivers which do not do anything special in module
+ *  init/exit, for eliminating a boilerplate code.
+ */
+#define module_mei_cl_driver(__mei_cldrv) \
+	module_driver(__mei_cldrv, \
+		      mei_cldev_driver_register,\
+		      mei_cldev_driver_unregister)
+
 ssize_t mei_cldev_send(struct mei_cl_device *cldev, u8 *buf, size_t length);
 ssize_t  mei_cldev_recv(struct mei_cl_device *cldev, u8 *buf, size_t length);
 
-- 
2.7.4

^ permalink raw reply related

* [char-misc-next 3/5] nfc: mei: use module_mei_cl_driver macro
From: Tomas Winkler @ 2016-10-19 13:33 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Aloisio Almeida Jr, Samuel Ortiz,
	Wim Van Sebroeck, Guenter Roeck
  Cc: Alexander Usyskin, linux-kernel, linux-wireless, linux-watchdog,
	Tomas Winkler
In-Reply-To: <1476884011-20645-1-git-send-email-tomas.winkler@intel.com>

Replace boilerplate driver registration with module_mei_cl_driver
macro in pn544 and microread devices.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/nfc/microread/mei.c | 23 +----------------------
 drivers/nfc/pn544/mei.c     | 23 +----------------------
 2 files changed, 2 insertions(+), 44 deletions(-)

diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c
index 3092501f26c4..eb5eddf1794e 100644
--- a/drivers/nfc/microread/mei.c
+++ b/drivers/nfc/microread/mei.c
@@ -82,28 +82,7 @@ static struct mei_cl_driver microread_driver = {
 	.remove = microread_mei_remove,
 };
 
-static int microread_mei_init(void)
-{
-	int r;
-
-	pr_debug(DRIVER_DESC ": %s\n", __func__);
-
-	r = mei_cldev_driver_register(&microread_driver);
-	if (r) {
-		pr_err(MICROREAD_DRIVER_NAME ": driver registration failed\n");
-		return r;
-	}
-
-	return 0;
-}
-
-static void microread_mei_exit(void)
-{
-	mei_cldev_driver_unregister(&microread_driver);
-}
-
-module_init(microread_mei_init);
-module_exit(microread_mei_exit);
+module_mei_cl_driver(microread_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/pn544/mei.c b/drivers/nfc/pn544/mei.c
index 46d0eb24eef9..ad57a8ec00d6 100644
--- a/drivers/nfc/pn544/mei.c
+++ b/drivers/nfc/pn544/mei.c
@@ -82,28 +82,7 @@ static struct mei_cl_driver pn544_driver = {
 	.remove = pn544_mei_remove,
 };
 
-static int pn544_mei_init(void)
-{
-	int r;
-
-	pr_debug(DRIVER_DESC ": %s\n", __func__);
-
-	r = mei_cldev_driver_register(&pn544_driver);
-	if (r) {
-		pr_err(PN544_DRIVER_NAME ": driver registration failed\n");
-		return r;
-	}
-
-	return 0;
-}
-
-static void pn544_mei_exit(void)
-{
-	mei_cldev_driver_unregister(&pn544_driver);
-}
-
-module_init(pn544_mei_init);
-module_exit(pn544_mei_exit);
+module_mei_cl_driver(pn544_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION(DRIVER_DESC);
-- 
2.7.4

^ permalink raw reply related

* [char-misc-next 4/5] nfc: mei_phy: get phy from the driver data
From: Tomas Winkler @ 2016-10-19 13:33 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Aloisio Almeida Jr, Samuel Ortiz,
	Wim Van Sebroeck, Guenter Roeck
  Cc: Alexander Usyskin, linux-kernel, linux-wireless, linux-watchdog,
	Tomas Winkler
In-Reply-To: <1476884011-20645-1-git-send-email-tomas.winkler@intel.com>

In order to remove rather redundant context from the callback
signature we the get nfc mei_phy from the driver's data.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
 drivers/nfc/mei_phy.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c
index 83deda4bb4d6..66dfd81ffb18 100644
--- a/drivers/nfc/mei_phy.c
+++ b/drivers/nfc/mei_phy.c
@@ -300,7 +300,10 @@ static int mei_nfc_recv(struct nfc_mei_phy *phy, u8 *buf, size_t length)
 static void nfc_mei_event_cb(struct mei_cl_device *cldev, u32 events,
 			     void *context)
 {
-	struct nfc_mei_phy *phy = context;
+	struct nfc_mei_phy *phy = mei_cldev_get_drvdata(cldev);
+
+	if (!phy)
+		return;
 
 	if (phy->hard_fault != 0)
 		return;
-- 
2.7.4

^ 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