mac80211: mark patches accepted upstream
authorNick Hainke <vincent@systemli.org>
Sat, 18 Mar 2023 18:43:22 +0000 (19:43 +0100)
committerChristian Marangi <ansuelsmth@gmail.com>
Sun, 19 Mar 2023 17:10:36 +0000 (18:10 +0100)
Add kernel tags to the patches that got accepted upstream.

Signed-off-by: Nick Hainke <vincent@systemli.org>
30 files changed:
package/kernel/mac80211/patches/subsys/306-01-v6.2-wifi-mac80211-add-internal-handler-for-wake_tx_queue.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/306-01-wifi-mac80211-add-internal-handler-for-wake_tx_queue.patch [deleted file]
package/kernel/mac80211/patches/subsys/306-02-v6.2-wifi-mac80211-add-wake_tx_queue-callback-to-drivers.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/306-02-wifi-mac80211-add-wake_tx_queue-callback-to-drivers.patch [deleted file]
package/kernel/mac80211/patches/subsys/306-03-v6.2-wifi-mac80211-Drop-support-for-TX-push-path.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/306-03-wifi-mac80211-Drop-support-for-TX-push-path.patch [deleted file]
package/kernel/mac80211/patches/subsys/306-04-v6.2-wifi-realtek-remove-duplicated-wake_tx_queue.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/306-04-wifi-realtek-remove-duplicated-wake_tx_queue.patch [deleted file]
package/kernel/mac80211/patches/subsys/307-v6.2-wifi-mac80211-fix-initialization-of-rx-link-and-rx-l.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/307-wifi-mac80211-fix-initialization-of-rx-link-and-rx-l.patch [deleted file]
package/kernel/mac80211/patches/subsys/308-v6.2-wifi-mac80211-fix-MLO-AP_VLAN-check.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/308-wifi-mac80211-fix-MLO-AP_VLAN-check.patch [deleted file]
package/kernel/mac80211/patches/subsys/310-mac80211-add-support-for-restricting-netdev-features.patch [deleted file]
package/kernel/mac80211/patches/subsys/310-v6.2-mac80211-add-support-for-restricting-netdev-features.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/311-v6.2-wifi-mac80211-fix-and-simplify-unencrypted-drop-chec.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/311-wifi-mac80211-fix-and-simplify-unencrypted-drop-chec.patch [deleted file]
package/kernel/mac80211/patches/subsys/312-v6.3-wifi-cfg80211-move-A-MSDU-check-in-ieee80211_data_to.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/312-wifi-cfg80211-move-A-MSDU-check-in-ieee80211_data_to.patch [deleted file]
package/kernel/mac80211/patches/subsys/313-v6.3-wifi-cfg80211-factor-out-bridge-tunnel-RFC1042-heade.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/313-wifi-cfg80211-factor-out-bridge-tunnel-RFC1042-heade.patch [deleted file]
package/kernel/mac80211/patches/subsys/314-v6.3-wifi-mac80211-remove-mesh-forwarding-congestion-chec.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/314-wifi-mac80211-remove-mesh-forwarding-congestion-chec.patch [deleted file]
package/kernel/mac80211/patches/subsys/315-v6.3-wifi-mac80211-fix-receiving-A-MSDU-frames-on-mesh-in.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/315-wifi-mac80211-fix-receiving-A-MSDU-frames-on-mesh-in.patch [deleted file]
package/kernel/mac80211/patches/subsys/316-v6.3-wifi-mac80211-add-a-workaround-for-receiving-non-sta.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/316-wifi-mac80211-add-a-workaround-for-receiving-non-sta.patch [deleted file]
package/kernel/mac80211/patches/subsys/323-v6.3-wifi-mac80211-Add-VHT-MU-MIMO-related-flags-in-ieee8.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/323-wifi-mac80211-Add-VHT-MU-MIMO-related-flags-in-ieee8.patch [deleted file]
package/kernel/mac80211/patches/subsys/324-v6.3-wifi-mac80211-Add-HE-MU-MIMO-related-flags-in-ieee80.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/324-wifi-mac80211-Add-HE-MU-MIMO-related-flags-in-ieee80.patch [deleted file]

diff --git a/package/kernel/mac80211/patches/subsys/306-01-v6.2-wifi-mac80211-add-internal-handler-for-wake_tx_queue.patch b/package/kernel/mac80211/patches/subsys/306-01-v6.2-wifi-mac80211-add-internal-handler-for-wake_tx_queue.patch
new file mode 100644 (file)
index 0000000..7686983
--- /dev/null
@@ -0,0 +1,192 @@
+From: Alexander Wetzel <alexander@wetzel-home.de>
+Date: Sun, 9 Oct 2022 18:30:38 +0200
+Subject: [PATCH] wifi: mac80211: add internal handler for wake_tx_queue
+
+Start to align the TX handling to only use internal TX queues (iTXQs):
+
+Provide a handler for drivers not having a custom wake_tx_queue
+callback and update the documentation.
+
+Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -89,15 +89,13 @@
+ /**
+  * DOC: mac80211 software tx queueing
+  *
+- * mac80211 provides an optional intermediate queueing implementation designed
+- * to allow the driver to keep hardware queues short and provide some fairness
+- * between different stations/interfaces.
+- * In this model, the driver pulls data frames from the mac80211 queue instead
+- * of letting mac80211 push them via drv_tx().
+- * Other frames (e.g. control or management) are still pushed using drv_tx().
++ * mac80211 uses an intermediate queueing implementation, designed to allow the
++ * driver to keep hardware queues short and to provide some fairness between
++ * different stations/interfaces.
+  *
+- * Drivers indicate that they use this model by implementing the .wake_tx_queue
+- * driver operation.
++ * Drivers must provide the .wake_tx_queue driver operation by either
++ * linking it to ieee80211_handle_wake_tx_queue() or implementing a custom
++ * handler.
+  *
+  * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with
+  * another per-sta for non-data/non-mgmt and bufferable management frames, and
+@@ -106,9 +104,12 @@
+  * The driver is expected to initialize its private per-queue data for stations
+  * and interfaces in the .add_interface and .sta_add ops.
+  *
+- * The driver can't access the queue directly. To dequeue a frame from a
+- * txq, it calls ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a
+- * queue, it calls the .wake_tx_queue driver op.
++ * The driver can't access the internal TX queues (iTXQs) directly.
++ * Whenever mac80211 adds a new frame to a queue, it calls the .wake_tx_queue
++ * driver op.
++ * Drivers implementing a custom .wake_tx_queue op can get them by calling
++ * ieee80211_tx_dequeue(). Drivers using ieee80211_handle_wake_tx_queue() will
++ * simply get the individual frames pushed via the .tx driver operation.
+  *
+  * Drivers can optionally delegate responsibility for scheduling queues to
+  * mac80211, to take advantage of airtime fairness accounting. In this case, to
+@@ -1826,7 +1827,7 @@ struct ieee80211_vif_cfg {
+  *    for this interface.
+  * @drv_priv: data area for driver use, will always be aligned to
+  *    sizeof(void \*).
+- * @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
++ * @txq: the multicast data TX queue
+  * @txqs_stopped: per AC flag to indicate that intermediate TXQs are stopped,
+  *    protected by fq->lock.
+  * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
+@@ -2252,8 +2253,8 @@ struct ieee80211_link_sta {
+  *    For non MLO STA it will point to the deflink data. For MLO STA
+  *    ieee80211_sta_recalc_aggregates() must be called to update it.
+  * @support_p2p_ps: indicates whether the STA supports P2P PS mechanism or not.
+- * @txq: per-TID data TX queues (if driver uses the TXQ abstraction); note that
+- *    the last entry (%IEEE80211_NUM_TIDS) is used for non-data frames
++ * @txq: per-TID data TX queues; note that the last entry (%IEEE80211_NUM_TIDS)
++ *    is used for non-data frames
+  * @deflink: This holds the default link STA information, for non MLO STA all link
+  *    specific STA information is accessed through @deflink or through
+  *    link[0] which points to address of @deflink. For MLO Link STA
+@@ -5691,7 +5692,7 @@ void ieee80211_key_replay(struct ieee802
+  * @hw: pointer as obtained from ieee80211_alloc_hw().
+  * @queue: queue number (counted from zero).
+  *
+- * Drivers should use this function instead of netif_wake_queue.
++ * Drivers must use this function instead of netif_wake_queue.
+  */
+ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue);
+@@ -5700,7 +5701,7 @@ void ieee80211_wake_queue(struct ieee802
+  * @hw: pointer as obtained from ieee80211_alloc_hw().
+  * @queue: queue number (counted from zero).
+  *
+- * Drivers should use this function instead of netif_stop_queue.
++ * Drivers must use this function instead of netif_stop_queue.
+  */
+ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);
+@@ -5709,7 +5710,7 @@ void ieee80211_stop_queue(struct ieee802
+  * @hw: pointer as obtained from ieee80211_alloc_hw().
+  * @queue: queue number (counted from zero).
+  *
+- * Drivers should use this function instead of netif_stop_queue.
++ * Drivers must use this function instead of netif_queue_stopped.
+  *
+  * Return: %true if the queue is stopped. %false otherwise.
+  */
+@@ -5720,7 +5721,7 @@ int ieee80211_queue_stopped(struct ieee8
+  * ieee80211_stop_queues - stop all queues
+  * @hw: pointer as obtained from ieee80211_alloc_hw().
+  *
+- * Drivers should use this function instead of netif_stop_queue.
++ * Drivers must use this function instead of netif_tx_stop_all_queues.
+  */
+ void ieee80211_stop_queues(struct ieee80211_hw *hw);
+@@ -5728,7 +5729,7 @@ void ieee80211_stop_queues(struct ieee80
+  * ieee80211_wake_queues - wake all queues
+  * @hw: pointer as obtained from ieee80211_alloc_hw().
+  *
+- * Drivers should use this function instead of netif_wake_queue.
++ * Drivers must use this function instead of netif_tx_wake_all_queues.
+  */
+ void ieee80211_wake_queues(struct ieee80211_hw *hw);
+@@ -6950,6 +6951,18 @@ static inline struct sk_buff *ieee80211_
+ }
+ /**
++ * ieee80211_handle_wake_tx_queue - mac80211 handler for wake_tx_queue callback
++ *
++ * @hw: pointer as obtained from wake_tx_queue() callback().
++ * @txq: pointer as obtained from wake_tx_queue() callback().
++ *
++ * Drivers can use this function for the mandatory mac80211 wake_tx_queue
++ * callback in struct ieee80211_ops. They should not call this function.
++ */
++void ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,
++                                  struct ieee80211_txq *txq);
++
++/**
+  * ieee80211_next_txq - get next tx queue to pull packets from
+  *
+  * @hw: pointer as obtained from ieee80211_alloc_hw()
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -288,6 +288,52 @@ __le16 ieee80211_ctstoself_duration(stru
+ }
+ EXPORT_SYMBOL(ieee80211_ctstoself_duration);
++static void wake_tx_push_queue(struct ieee80211_local *local,
++                             struct ieee80211_sub_if_data *sdata,
++                             struct ieee80211_txq *queue)
++{
++      int q = sdata->vif.hw_queue[queue->ac];
++      struct ieee80211_tx_control control = {
++              .sta = queue->sta,
++      };
++      struct sk_buff *skb;
++      unsigned long flags;
++      bool q_stopped;
++
++      while (1) {
++              spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
++              q_stopped = local->queue_stop_reasons[q];
++              spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
++
++              if (q_stopped)
++                      break;
++
++              skb = ieee80211_tx_dequeue(&local->hw, queue);
++              if (!skb)
++                      break;
++
++              drv_tx(local, &control, skb);
++      }
++}
++
++/* wake_tx_queue handler for driver not implementing a custom one*/
++void ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,
++                                  struct ieee80211_txq *txq)
++{
++      struct ieee80211_local *local = hw_to_local(hw);
++      struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);
++      struct ieee80211_txq *queue;
++
++      /* Use ieee80211_next_txq() for airtime fairness accounting */
++      ieee80211_txq_schedule_start(hw, txq->ac);
++      while ((queue = ieee80211_next_txq(hw, txq->ac))) {
++              wake_tx_push_queue(local, sdata, queue);
++              ieee80211_return_txq(hw, queue, false);
++      }
++      ieee80211_txq_schedule_end(hw, txq->ac);
++}
++EXPORT_SYMBOL(ieee80211_handle_wake_tx_queue);
++
+ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
+ {
+       struct ieee80211_local *local = sdata->local;
diff --git a/package/kernel/mac80211/patches/subsys/306-01-wifi-mac80211-add-internal-handler-for-wake_tx_queue.patch b/package/kernel/mac80211/patches/subsys/306-01-wifi-mac80211-add-internal-handler-for-wake_tx_queue.patch
deleted file mode 100644 (file)
index 7686983..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-From: Alexander Wetzel <alexander@wetzel-home.de>
-Date: Sun, 9 Oct 2022 18:30:38 +0200
-Subject: [PATCH] wifi: mac80211: add internal handler for wake_tx_queue
-
-Start to align the TX handling to only use internal TX queues (iTXQs):
-
-Provide a handler for drivers not having a custom wake_tx_queue
-callback and update the documentation.
-
-Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -89,15 +89,13 @@
- /**
-  * DOC: mac80211 software tx queueing
-  *
-- * mac80211 provides an optional intermediate queueing implementation designed
-- * to allow the driver to keep hardware queues short and provide some fairness
-- * between different stations/interfaces.
-- * In this model, the driver pulls data frames from the mac80211 queue instead
-- * of letting mac80211 push them via drv_tx().
-- * Other frames (e.g. control or management) are still pushed using drv_tx().
-+ * mac80211 uses an intermediate queueing implementation, designed to allow the
-+ * driver to keep hardware queues short and to provide some fairness between
-+ * different stations/interfaces.
-  *
-- * Drivers indicate that they use this model by implementing the .wake_tx_queue
-- * driver operation.
-+ * Drivers must provide the .wake_tx_queue driver operation by either
-+ * linking it to ieee80211_handle_wake_tx_queue() or implementing a custom
-+ * handler.
-  *
-  * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with
-  * another per-sta for non-data/non-mgmt and bufferable management frames, and
-@@ -106,9 +104,12 @@
-  * The driver is expected to initialize its private per-queue data for stations
-  * and interfaces in the .add_interface and .sta_add ops.
-  *
-- * The driver can't access the queue directly. To dequeue a frame from a
-- * txq, it calls ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a
-- * queue, it calls the .wake_tx_queue driver op.
-+ * The driver can't access the internal TX queues (iTXQs) directly.
-+ * Whenever mac80211 adds a new frame to a queue, it calls the .wake_tx_queue
-+ * driver op.
-+ * Drivers implementing a custom .wake_tx_queue op can get them by calling
-+ * ieee80211_tx_dequeue(). Drivers using ieee80211_handle_wake_tx_queue() will
-+ * simply get the individual frames pushed via the .tx driver operation.
-  *
-  * Drivers can optionally delegate responsibility for scheduling queues to
-  * mac80211, to take advantage of airtime fairness accounting. In this case, to
-@@ -1826,7 +1827,7 @@ struct ieee80211_vif_cfg {
-  *    for this interface.
-  * @drv_priv: data area for driver use, will always be aligned to
-  *    sizeof(void \*).
-- * @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
-+ * @txq: the multicast data TX queue
-  * @txqs_stopped: per AC flag to indicate that intermediate TXQs are stopped,
-  *    protected by fq->lock.
-  * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
-@@ -2252,8 +2253,8 @@ struct ieee80211_link_sta {
-  *    For non MLO STA it will point to the deflink data. For MLO STA
-  *    ieee80211_sta_recalc_aggregates() must be called to update it.
-  * @support_p2p_ps: indicates whether the STA supports P2P PS mechanism or not.
-- * @txq: per-TID data TX queues (if driver uses the TXQ abstraction); note that
-- *    the last entry (%IEEE80211_NUM_TIDS) is used for non-data frames
-+ * @txq: per-TID data TX queues; note that the last entry (%IEEE80211_NUM_TIDS)
-+ *    is used for non-data frames
-  * @deflink: This holds the default link STA information, for non MLO STA all link
-  *    specific STA information is accessed through @deflink or through
-  *    link[0] which points to address of @deflink. For MLO Link STA
-@@ -5691,7 +5692,7 @@ void ieee80211_key_replay(struct ieee802
-  * @hw: pointer as obtained from ieee80211_alloc_hw().
-  * @queue: queue number (counted from zero).
-  *
-- * Drivers should use this function instead of netif_wake_queue.
-+ * Drivers must use this function instead of netif_wake_queue.
-  */
- void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue);
-@@ -5700,7 +5701,7 @@ void ieee80211_wake_queue(struct ieee802
-  * @hw: pointer as obtained from ieee80211_alloc_hw().
-  * @queue: queue number (counted from zero).
-  *
-- * Drivers should use this function instead of netif_stop_queue.
-+ * Drivers must use this function instead of netif_stop_queue.
-  */
- void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);
-@@ -5709,7 +5710,7 @@ void ieee80211_stop_queue(struct ieee802
-  * @hw: pointer as obtained from ieee80211_alloc_hw().
-  * @queue: queue number (counted from zero).
-  *
-- * Drivers should use this function instead of netif_stop_queue.
-+ * Drivers must use this function instead of netif_queue_stopped.
-  *
-  * Return: %true if the queue is stopped. %false otherwise.
-  */
-@@ -5720,7 +5721,7 @@ int ieee80211_queue_stopped(struct ieee8
-  * ieee80211_stop_queues - stop all queues
-  * @hw: pointer as obtained from ieee80211_alloc_hw().
-  *
-- * Drivers should use this function instead of netif_stop_queue.
-+ * Drivers must use this function instead of netif_tx_stop_all_queues.
-  */
- void ieee80211_stop_queues(struct ieee80211_hw *hw);
-@@ -5728,7 +5729,7 @@ void ieee80211_stop_queues(struct ieee80
-  * ieee80211_wake_queues - wake all queues
-  * @hw: pointer as obtained from ieee80211_alloc_hw().
-  *
-- * Drivers should use this function instead of netif_wake_queue.
-+ * Drivers must use this function instead of netif_tx_wake_all_queues.
-  */
- void ieee80211_wake_queues(struct ieee80211_hw *hw);
-@@ -6950,6 +6951,18 @@ static inline struct sk_buff *ieee80211_
- }
- /**
-+ * ieee80211_handle_wake_tx_queue - mac80211 handler for wake_tx_queue callback
-+ *
-+ * @hw: pointer as obtained from wake_tx_queue() callback().
-+ * @txq: pointer as obtained from wake_tx_queue() callback().
-+ *
-+ * Drivers can use this function for the mandatory mac80211 wake_tx_queue
-+ * callback in struct ieee80211_ops. They should not call this function.
-+ */
-+void ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,
-+                                  struct ieee80211_txq *txq);
-+
-+/**
-  * ieee80211_next_txq - get next tx queue to pull packets from
-  *
-  * @hw: pointer as obtained from ieee80211_alloc_hw()
---- a/net/mac80211/util.c
-+++ b/net/mac80211/util.c
-@@ -288,6 +288,52 @@ __le16 ieee80211_ctstoself_duration(stru
- }
- EXPORT_SYMBOL(ieee80211_ctstoself_duration);
-+static void wake_tx_push_queue(struct ieee80211_local *local,
-+                             struct ieee80211_sub_if_data *sdata,
-+                             struct ieee80211_txq *queue)
-+{
-+      int q = sdata->vif.hw_queue[queue->ac];
-+      struct ieee80211_tx_control control = {
-+              .sta = queue->sta,
-+      };
-+      struct sk_buff *skb;
-+      unsigned long flags;
-+      bool q_stopped;
-+
-+      while (1) {
-+              spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-+              q_stopped = local->queue_stop_reasons[q];
-+              spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-+
-+              if (q_stopped)
-+                      break;
-+
-+              skb = ieee80211_tx_dequeue(&local->hw, queue);
-+              if (!skb)
-+                      break;
-+
-+              drv_tx(local, &control, skb);
-+      }
-+}
-+
-+/* wake_tx_queue handler for driver not implementing a custom one*/
-+void ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,
-+                                  struct ieee80211_txq *txq)
-+{
-+      struct ieee80211_local *local = hw_to_local(hw);
-+      struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);
-+      struct ieee80211_txq *queue;
-+
-+      /* Use ieee80211_next_txq() for airtime fairness accounting */
-+      ieee80211_txq_schedule_start(hw, txq->ac);
-+      while ((queue = ieee80211_next_txq(hw, txq->ac))) {
-+              wake_tx_push_queue(local, sdata, queue);
-+              ieee80211_return_txq(hw, queue, false);
-+      }
-+      ieee80211_txq_schedule_end(hw, txq->ac);
-+}
-+EXPORT_SYMBOL(ieee80211_handle_wake_tx_queue);
-+
- static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
- {
-       struct ieee80211_local *local = sdata->local;
diff --git a/package/kernel/mac80211/patches/subsys/306-02-v6.2-wifi-mac80211-add-wake_tx_queue-callback-to-drivers.patch b/package/kernel/mac80211/patches/subsys/306-02-v6.2-wifi-mac80211-add-wake_tx_queue-callback-to-drivers.patch
new file mode 100644 (file)
index 0000000..8e2c205
--- /dev/null
@@ -0,0 +1,396 @@
+From: Alexander Wetzel <alexander@wetzel-home.de>
+Date: Sun, 9 Oct 2022 18:30:39 +0200
+Subject: [PATCH] wifi: mac80211: add wake_tx_queue callback to drivers
+
+mac80211 is fully switching over to the internal TX queue (iTXQ)
+implementation. Update all drivers not yet providing the now mandatory
+wake_tx_queue() callback.
+
+As an side effect the netdev interfaces of all updated drivers will
+switch to the noqueue qdisc.
+
+Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
+[add staging drivers]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/drivers/net/wireless/admtek/adm8211.c
++++ b/drivers/net/wireless/admtek/adm8211.c
+@@ -1760,6 +1760,7 @@ static int adm8211_alloc_rings(struct ie
+ static const struct ieee80211_ops adm8211_ops = {
+       .tx                     = adm8211_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = adm8211_start,
+       .stop                   = adm8211_stop,
+       .add_interface          = adm8211_add_interface,
+--- a/drivers/net/wireless/ath/ar5523/ar5523.c
++++ b/drivers/net/wireless/ath/ar5523/ar5523.c
+@@ -1355,6 +1355,7 @@ static const struct ieee80211_ops ar5523
+       .start                  = ar5523_start,
+       .stop                   = ar5523_stop,
+       .tx                     = ar5523_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .set_rts_threshold      = ar5523_set_rts_threshold,
+       .add_interface          = ar5523_add_interface,
+       .remove_interface       = ar5523_remove_interface,
+--- a/drivers/net/wireless/ath/ath11k/mac.c
++++ b/drivers/net/wireless/ath/ath11k/mac.c
+@@ -8539,6 +8539,7 @@ err_fallback:
+ static const struct ieee80211_ops ath11k_ops = {
+       .tx                             = ath11k_mac_op_tx,
++      .wake_tx_queue                  = ieee80211_handle_wake_tx_queue,
+       .start                          = ath11k_mac_op_start,
+       .stop                           = ath11k_mac_op_stop,
+       .reconfig_complete              = ath11k_mac_op_reconfig_complete,
+--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
++++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+@@ -781,6 +781,7 @@ static int ath5k_set_ringparam(struct ie
+ const struct ieee80211_ops ath5k_hw_ops = {
+       .tx                     = ath5k_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = ath5k_start,
+       .stop                   = ath5k_stop,
+       .add_interface          = ath5k_add_interface,
+--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
++++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+@@ -1870,6 +1870,7 @@ static void ath9k_htc_channel_switch_bea
+ struct ieee80211_ops ath9k_htc_ops = {
+       .tx                 = ath9k_htc_tx,
++      .wake_tx_queue      = ieee80211_handle_wake_tx_queue,
+       .start              = ath9k_htc_start,
+       .stop               = ath9k_htc_stop,
+       .add_interface      = ath9k_htc_add_interface,
+--- a/drivers/net/wireless/ath/carl9170/main.c
++++ b/drivers/net/wireless/ath/carl9170/main.c
+@@ -1715,6 +1715,7 @@ static const struct ieee80211_ops carl91
+       .start                  = carl9170_op_start,
+       .stop                   = carl9170_op_stop,
+       .tx                     = carl9170_op_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .flush                  = carl9170_op_flush,
+       .add_interface          = carl9170_op_add_interface,
+       .remove_interface       = carl9170_op_remove_interface,
+--- a/drivers/net/wireless/ath/wcn36xx/main.c
++++ b/drivers/net/wireless/ath/wcn36xx/main.c
+@@ -1362,6 +1362,7 @@ static const struct ieee80211_ops wcn36x
+       .prepare_multicast      = wcn36xx_prepare_multicast,
+       .configure_filter       = wcn36xx_configure_filter,
+       .tx                     = wcn36xx_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .set_key                = wcn36xx_set_key,
+       .hw_scan                = wcn36xx_hw_scan,
+       .cancel_hw_scan         = wcn36xx_cancel_hw_scan,
+--- a/drivers/net/wireless/atmel/at76c50x-usb.c
++++ b/drivers/net/wireless/atmel/at76c50x-usb.c
+@@ -2187,6 +2187,7 @@ static int at76_set_key(struct ieee80211
+ static const struct ieee80211_ops at76_ops = {
+       .tx = at76_mac80211_tx,
++      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
+       .add_interface = at76_add_interface,
+       .remove_interface = at76_remove_interface,
+       .config = at76_config,
+--- a/drivers/net/wireless/broadcom/b43/main.c
++++ b/drivers/net/wireless/broadcom/b43/main.c
+@@ -5171,6 +5171,7 @@ static int b43_op_get_survey(struct ieee
+ static const struct ieee80211_ops b43_hw_ops = {
+       .tx                     = b43_op_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .conf_tx                = b43_op_conf_tx,
+       .add_interface          = b43_op_add_interface,
+       .remove_interface       = b43_op_remove_interface,
+--- a/drivers/net/wireless/broadcom/b43legacy/main.c
++++ b/drivers/net/wireless/broadcom/b43legacy/main.c
+@@ -3532,6 +3532,7 @@ static int b43legacy_op_get_survey(struc
+ static const struct ieee80211_ops b43legacy_hw_ops = {
+       .tx                     = b43legacy_op_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .conf_tx                = b43legacy_op_conf_tx,
+       .add_interface          = b43legacy_op_add_interface,
+       .remove_interface       = b43legacy_op_remove_interface,
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
+@@ -962,6 +962,7 @@ static int brcms_ops_beacon_set_tim(stru
+ static const struct ieee80211_ops brcms_ops = {
+       .tx = brcms_ops_tx,
++      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
+       .start = brcms_ops_start,
+       .stop = brcms_ops_stop,
+       .add_interface = brcms_ops_add_interface,
+--- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c
++++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
+@@ -3435,6 +3435,7 @@ static const struct attribute_group il39
+ static struct ieee80211_ops il3945_mac_ops __ro_after_init = {
+       .tx = il3945_mac_tx,
++      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
+       .start = il3945_mac_start,
+       .stop = il3945_mac_stop,
+       .add_interface = il_mac_add_interface,
+--- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c
++++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
+@@ -6304,6 +6304,7 @@ il4965_tx_queue_set_status(struct il_pri
+ static const struct ieee80211_ops il4965_mac_ops = {
+       .tx = il4965_mac_tx,
++      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
+       .start = il4965_mac_start,
+       .stop = il4965_mac_stop,
+       .add_interface = il_mac_add_interface,
+--- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
++++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
+@@ -1571,6 +1571,7 @@ static void iwlagn_mac_sta_notify(struct
+ const struct ieee80211_ops iwlagn_hw_ops = {
+       .tx = iwlagn_mac_tx,
++      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
+       .start = iwlagn_mac_start,
+       .stop = iwlagn_mac_stop,
+ #ifdef CONFIG_PM_SLEEP
+--- a/drivers/net/wireless/intersil/p54/main.c
++++ b/drivers/net/wireless/intersil/p54/main.c
+@@ -705,6 +705,7 @@ static void p54_set_coverage_class(struc
+ static const struct ieee80211_ops p54_ops = {
+       .tx                     = p54_tx_80211,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = p54_start,
+       .stop                   = p54_stop,
+       .add_interface          = p54_add_interface,
+--- a/drivers/net/wireless/mac80211_hwsim.c
++++ b/drivers/net/wireless/mac80211_hwsim.c
+@@ -3109,6 +3109,7 @@ static int mac80211_hwsim_change_sta_lin
+ #define HWSIM_COMMON_OPS                                      \
+       .tx = mac80211_hwsim_tx,                                \
++      .wake_tx_queue = ieee80211_handle_wake_tx_queue,        \
+       .start = mac80211_hwsim_start,                          \
+       .stop = mac80211_hwsim_stop,                            \
+       .add_interface = mac80211_hwsim_add_interface,          \
+--- a/drivers/net/wireless/marvell/libertas_tf/main.c
++++ b/drivers/net/wireless/marvell/libertas_tf/main.c
+@@ -474,6 +474,7 @@ static int lbtf_op_get_survey(struct iee
+ static const struct ieee80211_ops lbtf_ops = {
+       .tx                     = lbtf_op_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = lbtf_op_start,
+       .stop                   = lbtf_op_stop,
+       .add_interface          = lbtf_op_add_interface,
+--- a/drivers/net/wireless/marvell/mwl8k.c
++++ b/drivers/net/wireless/marvell/mwl8k.c
+@@ -5611,6 +5611,7 @@ static void mwl8k_sw_scan_complete(struc
+ static const struct ieee80211_ops mwl8k_ops = {
+       .tx                     = mwl8k_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = mwl8k_start,
+       .stop                   = mwl8k_stop,
+       .add_interface          = mwl8k_add_interface,
+--- a/drivers/net/wireless/mediatek/mt7601u/main.c
++++ b/drivers/net/wireless/mediatek/mt7601u/main.c
+@@ -406,6 +406,7 @@ out:
+ const struct ieee80211_ops mt7601u_ops = {
+       .tx = mt7601u_tx,
++      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
+       .start = mt7601u_start,
+       .stop = mt7601u_stop,
+       .add_interface = mt7601u_add_interface,
+--- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
+@@ -1706,6 +1706,7 @@ static int rt2400pci_tx_last_beacon(stru
+ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
+       .tx                     = rt2x00mac_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
+       .add_interface          = rt2x00mac_add_interface,
+--- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
+@@ -2004,6 +2004,7 @@ static int rt2500pci_tx_last_beacon(stru
+ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
+       .tx                     = rt2x00mac_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
+       .add_interface          = rt2x00mac_add_interface,
+--- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
+@@ -1795,6 +1795,7 @@ static int rt2500usb_probe_hw(struct rt2
+ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
+       .tx                     = rt2x00mac_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
+       .add_interface          = rt2x00mac_add_interface,
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+@@ -288,6 +288,7 @@ static int rt2800pci_read_eeprom(struct
+ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
+       .tx                     = rt2x00mac_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
+       .add_interface          = rt2x00mac_add_interface,
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+@@ -133,6 +133,7 @@ static int rt2800soc_write_firmware(stru
+ static const struct ieee80211_ops rt2800soc_mac80211_ops = {
+       .tx                     = rt2x00mac_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
+       .add_interface          = rt2x00mac_add_interface,
+--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+@@ -630,6 +630,7 @@ static int rt2800usb_probe_hw(struct rt2
+ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
+       .tx                     = rt2x00mac_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
+       .add_interface          = rt2x00mac_add_interface,
+--- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c
+@@ -2873,6 +2873,7 @@ static u64 rt61pci_get_tsf(struct ieee80
+ static const struct ieee80211_ops rt61pci_mac80211_ops = {
+       .tx                     = rt2x00mac_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
+       .add_interface          = rt2x00mac_add_interface,
+--- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c
++++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c
+@@ -2292,6 +2292,7 @@ static u64 rt73usb_get_tsf(struct ieee80
+ static const struct ieee80211_ops rt73usb_mac80211_ops = {
+       .tx                     = rt2x00mac_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = rt2x00mac_start,
+       .stop                   = rt2x00mac_stop,
+       .add_interface          = rt2x00mac_add_interface,
+--- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c
++++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c
+@@ -1608,6 +1608,7 @@ static void rtl8180_configure_filter(str
+ static const struct ieee80211_ops rtl8180_ops = {
+       .tx                     = rtl8180_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = rtl8180_start,
+       .stop                   = rtl8180_stop,
+       .add_interface          = rtl8180_add_interface,
+--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
++++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
+@@ -1378,6 +1378,7 @@ static int rtl8187_conf_tx(struct ieee80
+ static const struct ieee80211_ops rtl8187_ops = {
+       .tx                     = rtl8187_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = rtl8187_start,
+       .stop                   = rtl8187_stop,
+       .add_interface          = rtl8187_add_interface,
+--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
++++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
+@@ -6561,6 +6561,7 @@ static void rtl8xxxu_stop(struct ieee802
+ static const struct ieee80211_ops rtl8xxxu_ops = {
+       .tx = rtl8xxxu_tx,
++      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
+       .add_interface = rtl8xxxu_add_interface,
+       .remove_interface = rtl8xxxu_remove_interface,
+       .config = rtl8xxxu_config,
+--- a/drivers/net/wireless/realtek/rtlwifi/core.c
++++ b/drivers/net/wireless/realtek/rtlwifi/core.c
+@@ -1912,6 +1912,7 @@ const struct ieee80211_ops rtl_ops = {
+       .start = rtl_op_start,
+       .stop = rtl_op_stop,
+       .tx = rtl_op_tx,
++      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
+       .add_interface = rtl_op_add_interface,
+       .remove_interface = rtl_op_remove_interface,
+       .change_interface = rtl_op_change_interface,
+--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
++++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
+@@ -896,6 +896,7 @@ static void rtw_ops_sta_rc_update(struct
+ const struct ieee80211_ops rtw_ops = {
+       .tx                     = rtw_ops_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .wake_tx_queue          = rtw_ops_wake_tx_queue,
+       .start                  = rtw_ops_start,
+       .stop                   = rtw_ops_stop,
+--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
++++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
+@@ -918,6 +918,7 @@ static int rtw89_ops_set_tid_config(stru
+ const struct ieee80211_ops rtw89_ops = {
+       .tx                     = rtw89_ops_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .wake_tx_queue          = rtw89_ops_wake_tx_queue,
+       .start                  = rtw89_ops_start,
+       .stop                   = rtw89_ops_stop,
+--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
++++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+@@ -1958,6 +1958,7 @@ static int rsi_mac80211_resume(struct ie
+ static const struct ieee80211_ops mac80211_ops = {
+       .tx = rsi_mac80211_tx,
++      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
+       .start = rsi_mac80211_start,
+       .stop = rsi_mac80211_stop,
+       .add_interface = rsi_mac80211_add_interface,
+--- a/drivers/net/wireless/st/cw1200/main.c
++++ b/drivers/net/wireless/st/cw1200/main.c
+@@ -209,6 +209,7 @@ static const struct ieee80211_ops cw1200
+       .remove_interface       = cw1200_remove_interface,
+       .change_interface       = cw1200_change_interface,
+       .tx                     = cw1200_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .hw_scan                = cw1200_hw_scan,
+       .set_tim                = cw1200_set_tim,
+       .sta_notify             = cw1200_sta_notify,
+--- a/drivers/net/wireless/ti/wl1251/main.c
++++ b/drivers/net/wireless/ti/wl1251/main.c
+@@ -1359,6 +1359,7 @@ static const struct ieee80211_ops wl1251
+       .prepare_multicast = wl1251_op_prepare_multicast,
+       .configure_filter = wl1251_op_configure_filter,
+       .tx = wl1251_op_tx,
++      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
+       .set_key = wl1251_op_set_key,
+       .hw_scan = wl1251_op_hw_scan,
+       .bss_info_changed = wl1251_op_bss_info_changed,
+--- a/drivers/net/wireless/ti/wlcore/main.c
++++ b/drivers/net/wireless/ti/wlcore/main.c
+@@ -5942,6 +5942,7 @@ static const struct ieee80211_ops wl1271
+       .prepare_multicast = wl1271_op_prepare_multicast,
+       .configure_filter = wl1271_op_configure_filter,
+       .tx = wl1271_op_tx,
++      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
+       .set_key = wlcore_op_set_key,
+       .hw_scan = wl1271_op_hw_scan,
+       .cancel_hw_scan = wl1271_op_cancel_hw_scan,
+--- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
++++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
+@@ -1344,6 +1344,7 @@ static u64 zd_op_get_tsf(struct ieee8021
+ static const struct ieee80211_ops zd_ops = {
+       .tx                     = zd_op_tx,
++      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .start                  = zd_op_start,
+       .stop                   = zd_op_stop,
+       .add_interface          = zd_op_add_interface,
diff --git a/package/kernel/mac80211/patches/subsys/306-02-wifi-mac80211-add-wake_tx_queue-callback-to-drivers.patch b/package/kernel/mac80211/patches/subsys/306-02-wifi-mac80211-add-wake_tx_queue-callback-to-drivers.patch
deleted file mode 100644 (file)
index 8e2c205..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-From: Alexander Wetzel <alexander@wetzel-home.de>
-Date: Sun, 9 Oct 2022 18:30:39 +0200
-Subject: [PATCH] wifi: mac80211: add wake_tx_queue callback to drivers
-
-mac80211 is fully switching over to the internal TX queue (iTXQ)
-implementation. Update all drivers not yet providing the now mandatory
-wake_tx_queue() callback.
-
-As an side effect the netdev interfaces of all updated drivers will
-switch to the noqueue qdisc.
-
-Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
-[add staging drivers]
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/drivers/net/wireless/admtek/adm8211.c
-+++ b/drivers/net/wireless/admtek/adm8211.c
-@@ -1760,6 +1760,7 @@ static int adm8211_alloc_rings(struct ie
- static const struct ieee80211_ops adm8211_ops = {
-       .tx                     = adm8211_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = adm8211_start,
-       .stop                   = adm8211_stop,
-       .add_interface          = adm8211_add_interface,
---- a/drivers/net/wireless/ath/ar5523/ar5523.c
-+++ b/drivers/net/wireless/ath/ar5523/ar5523.c
-@@ -1355,6 +1355,7 @@ static const struct ieee80211_ops ar5523
-       .start                  = ar5523_start,
-       .stop                   = ar5523_stop,
-       .tx                     = ar5523_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .set_rts_threshold      = ar5523_set_rts_threshold,
-       .add_interface          = ar5523_add_interface,
-       .remove_interface       = ar5523_remove_interface,
---- a/drivers/net/wireless/ath/ath11k/mac.c
-+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -8539,6 +8539,7 @@ err_fallback:
- static const struct ieee80211_ops ath11k_ops = {
-       .tx                             = ath11k_mac_op_tx,
-+      .wake_tx_queue                  = ieee80211_handle_wake_tx_queue,
-       .start                          = ath11k_mac_op_start,
-       .stop                           = ath11k_mac_op_stop,
-       .reconfig_complete              = ath11k_mac_op_reconfig_complete,
---- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
-+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
-@@ -781,6 +781,7 @@ static int ath5k_set_ringparam(struct ie
- const struct ieee80211_ops ath5k_hw_ops = {
-       .tx                     = ath5k_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = ath5k_start,
-       .stop                   = ath5k_stop,
-       .add_interface          = ath5k_add_interface,
---- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
-+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
-@@ -1870,6 +1870,7 @@ static void ath9k_htc_channel_switch_bea
- struct ieee80211_ops ath9k_htc_ops = {
-       .tx                 = ath9k_htc_tx,
-+      .wake_tx_queue      = ieee80211_handle_wake_tx_queue,
-       .start              = ath9k_htc_start,
-       .stop               = ath9k_htc_stop,
-       .add_interface      = ath9k_htc_add_interface,
---- a/drivers/net/wireless/ath/carl9170/main.c
-+++ b/drivers/net/wireless/ath/carl9170/main.c
-@@ -1715,6 +1715,7 @@ static const struct ieee80211_ops carl91
-       .start                  = carl9170_op_start,
-       .stop                   = carl9170_op_stop,
-       .tx                     = carl9170_op_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .flush                  = carl9170_op_flush,
-       .add_interface          = carl9170_op_add_interface,
-       .remove_interface       = carl9170_op_remove_interface,
---- a/drivers/net/wireless/ath/wcn36xx/main.c
-+++ b/drivers/net/wireless/ath/wcn36xx/main.c
-@@ -1362,6 +1362,7 @@ static const struct ieee80211_ops wcn36x
-       .prepare_multicast      = wcn36xx_prepare_multicast,
-       .configure_filter       = wcn36xx_configure_filter,
-       .tx                     = wcn36xx_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .set_key                = wcn36xx_set_key,
-       .hw_scan                = wcn36xx_hw_scan,
-       .cancel_hw_scan         = wcn36xx_cancel_hw_scan,
---- a/drivers/net/wireless/atmel/at76c50x-usb.c
-+++ b/drivers/net/wireless/atmel/at76c50x-usb.c
-@@ -2187,6 +2187,7 @@ static int at76_set_key(struct ieee80211
- static const struct ieee80211_ops at76_ops = {
-       .tx = at76_mac80211_tx,
-+      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-       .add_interface = at76_add_interface,
-       .remove_interface = at76_remove_interface,
-       .config = at76_config,
---- a/drivers/net/wireless/broadcom/b43/main.c
-+++ b/drivers/net/wireless/broadcom/b43/main.c
-@@ -5171,6 +5171,7 @@ static int b43_op_get_survey(struct ieee
- static const struct ieee80211_ops b43_hw_ops = {
-       .tx                     = b43_op_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .conf_tx                = b43_op_conf_tx,
-       .add_interface          = b43_op_add_interface,
-       .remove_interface       = b43_op_remove_interface,
---- a/drivers/net/wireless/broadcom/b43legacy/main.c
-+++ b/drivers/net/wireless/broadcom/b43legacy/main.c
-@@ -3532,6 +3532,7 @@ static int b43legacy_op_get_survey(struc
- static const struct ieee80211_ops b43legacy_hw_ops = {
-       .tx                     = b43legacy_op_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .conf_tx                = b43legacy_op_conf_tx,
-       .add_interface          = b43legacy_op_add_interface,
-       .remove_interface       = b43legacy_op_remove_interface,
---- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c
-@@ -962,6 +962,7 @@ static int brcms_ops_beacon_set_tim(stru
- static const struct ieee80211_ops brcms_ops = {
-       .tx = brcms_ops_tx,
-+      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-       .start = brcms_ops_start,
-       .stop = brcms_ops_stop,
-       .add_interface = brcms_ops_add_interface,
---- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c
-+++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c
-@@ -3435,6 +3435,7 @@ static const struct attribute_group il39
- static struct ieee80211_ops il3945_mac_ops __ro_after_init = {
-       .tx = il3945_mac_tx,
-+      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-       .start = il3945_mac_start,
-       .stop = il3945_mac_stop,
-       .add_interface = il_mac_add_interface,
---- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c
-+++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c
-@@ -6304,6 +6304,7 @@ il4965_tx_queue_set_status(struct il_pri
- static const struct ieee80211_ops il4965_mac_ops = {
-       .tx = il4965_mac_tx,
-+      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-       .start = il4965_mac_start,
-       .stop = il4965_mac_stop,
-       .add_interface = il_mac_add_interface,
---- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
-+++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
-@@ -1571,6 +1571,7 @@ static void iwlagn_mac_sta_notify(struct
- const struct ieee80211_ops iwlagn_hw_ops = {
-       .tx = iwlagn_mac_tx,
-+      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-       .start = iwlagn_mac_start,
-       .stop = iwlagn_mac_stop,
- #ifdef CONFIG_PM_SLEEP
---- a/drivers/net/wireless/intersil/p54/main.c
-+++ b/drivers/net/wireless/intersil/p54/main.c
-@@ -705,6 +705,7 @@ static void p54_set_coverage_class(struc
- static const struct ieee80211_ops p54_ops = {
-       .tx                     = p54_tx_80211,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = p54_start,
-       .stop                   = p54_stop,
-       .add_interface          = p54_add_interface,
---- a/drivers/net/wireless/mac80211_hwsim.c
-+++ b/drivers/net/wireless/mac80211_hwsim.c
-@@ -3109,6 +3109,7 @@ static int mac80211_hwsim_change_sta_lin
- #define HWSIM_COMMON_OPS                                      \
-       .tx = mac80211_hwsim_tx,                                \
-+      .wake_tx_queue = ieee80211_handle_wake_tx_queue,        \
-       .start = mac80211_hwsim_start,                          \
-       .stop = mac80211_hwsim_stop,                            \
-       .add_interface = mac80211_hwsim_add_interface,          \
---- a/drivers/net/wireless/marvell/libertas_tf/main.c
-+++ b/drivers/net/wireless/marvell/libertas_tf/main.c
-@@ -474,6 +474,7 @@ static int lbtf_op_get_survey(struct iee
- static const struct ieee80211_ops lbtf_ops = {
-       .tx                     = lbtf_op_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = lbtf_op_start,
-       .stop                   = lbtf_op_stop,
-       .add_interface          = lbtf_op_add_interface,
---- a/drivers/net/wireless/marvell/mwl8k.c
-+++ b/drivers/net/wireless/marvell/mwl8k.c
-@@ -5611,6 +5611,7 @@ static void mwl8k_sw_scan_complete(struc
- static const struct ieee80211_ops mwl8k_ops = {
-       .tx                     = mwl8k_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = mwl8k_start,
-       .stop                   = mwl8k_stop,
-       .add_interface          = mwl8k_add_interface,
---- a/drivers/net/wireless/mediatek/mt7601u/main.c
-+++ b/drivers/net/wireless/mediatek/mt7601u/main.c
-@@ -406,6 +406,7 @@ out:
- const struct ieee80211_ops mt7601u_ops = {
-       .tx = mt7601u_tx,
-+      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-       .start = mt7601u_start,
-       .stop = mt7601u_stop,
-       .add_interface = mt7601u_add_interface,
---- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c
-@@ -1706,6 +1706,7 @@ static int rt2400pci_tx_last_beacon(stru
- static const struct ieee80211_ops rt2400pci_mac80211_ops = {
-       .tx                     = rt2x00mac_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = rt2x00mac_start,
-       .stop                   = rt2x00mac_stop,
-       .add_interface          = rt2x00mac_add_interface,
---- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c
-@@ -2004,6 +2004,7 @@ static int rt2500pci_tx_last_beacon(stru
- static const struct ieee80211_ops rt2500pci_mac80211_ops = {
-       .tx                     = rt2x00mac_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = rt2x00mac_start,
-       .stop                   = rt2x00mac_stop,
-       .add_interface          = rt2x00mac_add_interface,
---- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c
-@@ -1795,6 +1795,7 @@ static int rt2500usb_probe_hw(struct rt2
- static const struct ieee80211_ops rt2500usb_mac80211_ops = {
-       .tx                     = rt2x00mac_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = rt2x00mac_start,
-       .stop                   = rt2x00mac_stop,
-       .add_interface          = rt2x00mac_add_interface,
---- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
-@@ -288,6 +288,7 @@ static int rt2800pci_read_eeprom(struct
- static const struct ieee80211_ops rt2800pci_mac80211_ops = {
-       .tx                     = rt2x00mac_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = rt2x00mac_start,
-       .stop                   = rt2x00mac_stop,
-       .add_interface          = rt2x00mac_add_interface,
---- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
-@@ -133,6 +133,7 @@ static int rt2800soc_write_firmware(stru
- static const struct ieee80211_ops rt2800soc_mac80211_ops = {
-       .tx                     = rt2x00mac_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = rt2x00mac_start,
-       .stop                   = rt2x00mac_stop,
-       .add_interface          = rt2x00mac_add_interface,
---- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
-@@ -630,6 +630,7 @@ static int rt2800usb_probe_hw(struct rt2
- static const struct ieee80211_ops rt2800usb_mac80211_ops = {
-       .tx                     = rt2x00mac_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = rt2x00mac_start,
-       .stop                   = rt2x00mac_stop,
-       .add_interface          = rt2x00mac_add_interface,
---- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c
-@@ -2873,6 +2873,7 @@ static u64 rt61pci_get_tsf(struct ieee80
- static const struct ieee80211_ops rt61pci_mac80211_ops = {
-       .tx                     = rt2x00mac_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = rt2x00mac_start,
-       .stop                   = rt2x00mac_stop,
-       .add_interface          = rt2x00mac_add_interface,
---- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c
-+++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c
-@@ -2292,6 +2292,7 @@ static u64 rt73usb_get_tsf(struct ieee80
- static const struct ieee80211_ops rt73usb_mac80211_ops = {
-       .tx                     = rt2x00mac_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = rt2x00mac_start,
-       .stop                   = rt2x00mac_stop,
-       .add_interface          = rt2x00mac_add_interface,
---- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c
-+++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c
-@@ -1608,6 +1608,7 @@ static void rtl8180_configure_filter(str
- static const struct ieee80211_ops rtl8180_ops = {
-       .tx                     = rtl8180_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = rtl8180_start,
-       .stop                   = rtl8180_stop,
-       .add_interface          = rtl8180_add_interface,
---- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
-+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
-@@ -1378,6 +1378,7 @@ static int rtl8187_conf_tx(struct ieee80
- static const struct ieee80211_ops rtl8187_ops = {
-       .tx                     = rtl8187_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = rtl8187_start,
-       .stop                   = rtl8187_stop,
-       .add_interface          = rtl8187_add_interface,
---- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
-@@ -6561,6 +6561,7 @@ static void rtl8xxxu_stop(struct ieee802
- static const struct ieee80211_ops rtl8xxxu_ops = {
-       .tx = rtl8xxxu_tx,
-+      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-       .add_interface = rtl8xxxu_add_interface,
-       .remove_interface = rtl8xxxu_remove_interface,
-       .config = rtl8xxxu_config,
---- a/drivers/net/wireless/realtek/rtlwifi/core.c
-+++ b/drivers/net/wireless/realtek/rtlwifi/core.c
-@@ -1912,6 +1912,7 @@ const struct ieee80211_ops rtl_ops = {
-       .start = rtl_op_start,
-       .stop = rtl_op_stop,
-       .tx = rtl_op_tx,
-+      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-       .add_interface = rtl_op_add_interface,
-       .remove_interface = rtl_op_remove_interface,
-       .change_interface = rtl_op_change_interface,
---- a/drivers/net/wireless/realtek/rtw88/mac80211.c
-+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
-@@ -896,6 +896,7 @@ static void rtw_ops_sta_rc_update(struct
- const struct ieee80211_ops rtw_ops = {
-       .tx                     = rtw_ops_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .wake_tx_queue          = rtw_ops_wake_tx_queue,
-       .start                  = rtw_ops_start,
-       .stop                   = rtw_ops_stop,
---- a/drivers/net/wireless/realtek/rtw89/mac80211.c
-+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
-@@ -918,6 +918,7 @@ static int rtw89_ops_set_tid_config(stru
- const struct ieee80211_ops rtw89_ops = {
-       .tx                     = rtw89_ops_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .wake_tx_queue          = rtw89_ops_wake_tx_queue,
-       .start                  = rtw89_ops_start,
-       .stop                   = rtw89_ops_stop,
---- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
-+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
-@@ -1958,6 +1958,7 @@ static int rsi_mac80211_resume(struct ie
- static const struct ieee80211_ops mac80211_ops = {
-       .tx = rsi_mac80211_tx,
-+      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-       .start = rsi_mac80211_start,
-       .stop = rsi_mac80211_stop,
-       .add_interface = rsi_mac80211_add_interface,
---- a/drivers/net/wireless/st/cw1200/main.c
-+++ b/drivers/net/wireless/st/cw1200/main.c
-@@ -209,6 +209,7 @@ static const struct ieee80211_ops cw1200
-       .remove_interface       = cw1200_remove_interface,
-       .change_interface       = cw1200_change_interface,
-       .tx                     = cw1200_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .hw_scan                = cw1200_hw_scan,
-       .set_tim                = cw1200_set_tim,
-       .sta_notify             = cw1200_sta_notify,
---- a/drivers/net/wireless/ti/wl1251/main.c
-+++ b/drivers/net/wireless/ti/wl1251/main.c
-@@ -1359,6 +1359,7 @@ static const struct ieee80211_ops wl1251
-       .prepare_multicast = wl1251_op_prepare_multicast,
-       .configure_filter = wl1251_op_configure_filter,
-       .tx = wl1251_op_tx,
-+      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-       .set_key = wl1251_op_set_key,
-       .hw_scan = wl1251_op_hw_scan,
-       .bss_info_changed = wl1251_op_bss_info_changed,
---- a/drivers/net/wireless/ti/wlcore/main.c
-+++ b/drivers/net/wireless/ti/wlcore/main.c
-@@ -5942,6 +5942,7 @@ static const struct ieee80211_ops wl1271
-       .prepare_multicast = wl1271_op_prepare_multicast,
-       .configure_filter = wl1271_op_configure_filter,
-       .tx = wl1271_op_tx,
-+      .wake_tx_queue = ieee80211_handle_wake_tx_queue,
-       .set_key = wlcore_op_set_key,
-       .hw_scan = wl1271_op_hw_scan,
-       .cancel_hw_scan = wl1271_op_cancel_hw_scan,
---- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
-+++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c
-@@ -1344,6 +1344,7 @@ static u64 zd_op_get_tsf(struct ieee8021
- static const struct ieee80211_ops zd_ops = {
-       .tx                     = zd_op_tx,
-+      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .start                  = zd_op_start,
-       .stop                   = zd_op_stop,
-       .add_interface          = zd_op_add_interface,
diff --git a/package/kernel/mac80211/patches/subsys/306-03-v6.2-wifi-mac80211-Drop-support-for-TX-push-path.patch b/package/kernel/mac80211/patches/subsys/306-03-v6.2-wifi-mac80211-Drop-support-for-TX-push-path.patch
new file mode 100644 (file)
index 0000000..9d58345
--- /dev/null
@@ -0,0 +1,655 @@
+From: Alexander Wetzel <alexander@wetzel-home.de>
+Date: Sun, 9 Oct 2022 18:30:40 +0200
+Subject: [PATCH] wifi: mac80211: Drop support for TX push path
+
+All drivers are now using mac80211 internal queues (iTXQs).
+Drop mac80211 internal support for the old push path.
+
+Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -4339,9 +4339,6 @@ static int ieee80211_get_txq_stats(struc
+       struct ieee80211_sub_if_data *sdata;
+       int ret = 0;
+-      if (!local->ops->wake_tx_queue)
+-              return 1;
+-
+       spin_lock_bh(&local->fq.lock);
+       rcu_read_lock();
+--- a/net/mac80211/debugfs.c
++++ b/net/mac80211/debugfs.c
+@@ -663,9 +663,7 @@ void debugfs_hw_add(struct ieee80211_loc
+       DEBUGFS_ADD_MODE(force_tx_status, 0600);
+       DEBUGFS_ADD_MODE(aql_enable, 0600);
+       DEBUGFS_ADD(aql_pending);
+-
+-      if (local->ops->wake_tx_queue)
+-              DEBUGFS_ADD_MODE(aqm, 0600);
++      DEBUGFS_ADD_MODE(aqm, 0600);
+       DEBUGFS_ADD_MODE(airtime_flags, 0600);
+--- a/net/mac80211/debugfs_netdev.c
++++ b/net/mac80211/debugfs_netdev.c
+@@ -677,8 +677,7 @@ static void add_common_files(struct ieee
+       DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
+       DEBUGFS_ADD(hw_queues);
+-      if (sdata->local->ops->wake_tx_queue &&
+-          sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
++      if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
+           sdata->vif.type != NL80211_IFTYPE_NAN)
+               DEBUGFS_ADD(aqm);
+ }
+--- a/net/mac80211/debugfs_sta.c
++++ b/net/mac80211/debugfs_sta.c
+@@ -1056,10 +1056,8 @@ void ieee80211_sta_debugfs_add(struct st
+       DEBUGFS_ADD_COUNTER(rx_fragments, deflink.rx_stats.fragments);
+       DEBUGFS_ADD_COUNTER(tx_filtered, deflink.status_stats.filtered);
+-      if (local->ops->wake_tx_queue) {
+-              DEBUGFS_ADD(aqm);
+-              DEBUGFS_ADD(airtime);
+-      }
++      DEBUGFS_ADD(aqm);
++      DEBUGFS_ADD(airtime);
+       if (wiphy_ext_feature_isset(local->hw.wiphy,
+                                   NL80211_EXT_FEATURE_AQL))
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -2290,7 +2290,6 @@ void ieee80211_wake_queue_by_reason(stru
+ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
+                                   enum queue_stop_reason reason,
+                                   bool refcounted);
+-void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue);
+ void ieee80211_add_pending_skb(struct ieee80211_local *local,
+                              struct sk_buff *skb);
+ void ieee80211_add_pending_skbs(struct ieee80211_local *local,
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -458,12 +458,6 @@ static void ieee80211_do_stop(struct iee
+       if (cancel_scan)
+               ieee80211_scan_cancel(local);
+-      /*
+-       * Stop TX on this interface first.
+-       */
+-      if (!local->ops->wake_tx_queue && sdata->dev)
+-              netif_tx_stop_all_queues(sdata->dev);
+-
+       ieee80211_roc_purge(local, sdata);
+       switch (sdata->vif.type) {
+@@ -811,13 +805,6 @@ static void ieee80211_uninit(struct net_
+       ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev));
+ }
+-static u16 ieee80211_netdev_select_queue(struct net_device *dev,
+-                                       struct sk_buff *skb,
+-                                       struct net_device *sb_dev)
+-{
+-      return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
+-}
+-
+ static void
+ ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+ {
+@@ -831,7 +818,6 @@ static const struct net_device_ops ieee8
+       .ndo_start_xmit         = ieee80211_subif_start_xmit,
+       .ndo_set_rx_mode        = ieee80211_set_multicast_list,
+       .ndo_set_mac_address    = ieee80211_change_mac,
+-      .ndo_select_queue       = ieee80211_netdev_select_queue,
+       .ndo_get_stats64        = ieee80211_get_stats64,
+ };
+@@ -939,7 +925,6 @@ static const struct net_device_ops ieee8
+       .ndo_start_xmit         = ieee80211_subif_start_xmit_8023,
+       .ndo_set_rx_mode        = ieee80211_set_multicast_list,
+       .ndo_set_mac_address    = ieee80211_change_mac,
+-      .ndo_select_queue       = ieee80211_netdev_select_queue,
+       .ndo_get_stats64        = ieee80211_get_stats64,
+       .ndo_fill_forward_path  = ieee80211_netdev_fill_forward_path,
+ };
+@@ -1441,35 +1426,6 @@ int ieee80211_do_open(struct wireless_de
+       ieee80211_recalc_ps(local);
+-      if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+-          sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+-          local->ops->wake_tx_queue) {
+-              /* XXX: for AP_VLAN, actually track AP queues */
+-              if (dev)
+-                      netif_tx_start_all_queues(dev);
+-      } else if (dev) {
+-              unsigned long flags;
+-              int n_acs = IEEE80211_NUM_ACS;
+-              int ac;
+-
+-              if (local->hw.queues < IEEE80211_NUM_ACS)
+-                      n_acs = 1;
+-
+-              spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+-              if (sdata->vif.cab_queue == IEEE80211_INVAL_HW_QUEUE ||
+-                  (local->queue_stop_reasons[sdata->vif.cab_queue] == 0 &&
+-                   skb_queue_empty(&local->pending[sdata->vif.cab_queue]))) {
+-                      for (ac = 0; ac < n_acs; ac++) {
+-                              int ac_queue = sdata->vif.hw_queue[ac];
+-
+-                              if (local->queue_stop_reasons[ac_queue] == 0 &&
+-                                  skb_queue_empty(&local->pending[ac_queue]))
+-                                      netif_start_subqueue(dev, ac);
+-                      }
+-              }
+-              spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+-      }
+-
+       set_bit(SDATA_STATE_RUNNING, &sdata->state);
+       return 0;
+@@ -1499,17 +1455,12 @@ static void ieee80211_if_setup(struct ne
+ {
+       ether_setup(dev);
+       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
++      dev->priv_flags |= IFF_NO_QUEUE;
+       dev->netdev_ops = &ieee80211_dataif_ops;
+       dev->needs_free_netdev = true;
+       dev->priv_destructor = ieee80211_if_free;
+ }
+-static void ieee80211_if_setup_no_queue(struct net_device *dev)
+-{
+-      ieee80211_if_setup(dev);
+-      dev->priv_flags |= IFF_NO_QUEUE;
+-}
+-
+ static void ieee80211_iface_process_skb(struct ieee80211_local *local,
+                                       struct ieee80211_sub_if_data *sdata,
+                                       struct sk_buff *skb)
+@@ -2094,9 +2045,7 @@ int ieee80211_if_add(struct ieee80211_lo
+       struct net_device *ndev = NULL;
+       struct ieee80211_sub_if_data *sdata = NULL;
+       struct txq_info *txqi;
+-      void (*if_setup)(struct net_device *dev);
+       int ret, i;
+-      int txqs = 1;
+       ASSERT_RTNL();
+@@ -2119,30 +2068,18 @@ int ieee80211_if_add(struct ieee80211_lo
+                                sizeof(void *));
+               int txq_size = 0;
+-              if (local->ops->wake_tx_queue &&
+-                  type != NL80211_IFTYPE_AP_VLAN &&
++              if (type != NL80211_IFTYPE_AP_VLAN &&
+                   (type != NL80211_IFTYPE_MONITOR ||
+                    (params->flags & MONITOR_FLAG_ACTIVE)))
+                       txq_size += sizeof(struct txq_info) +
+                                   local->hw.txq_data_size;
+-              if (local->ops->wake_tx_queue) {
+-                      if_setup = ieee80211_if_setup_no_queue;
+-              } else {
+-                      if_setup = ieee80211_if_setup;
+-                      if (local->hw.queues >= IEEE80211_NUM_ACS)
+-                              txqs = IEEE80211_NUM_ACS;
+-              }
+-
+               ndev = alloc_netdev_mqs(size + txq_size,
+                                       name, name_assign_type,
+-                                      if_setup, txqs, 1);
++                                      ieee80211_if_setup, 1, 1);
+               if (!ndev)
+                       return -ENOMEM;
+-              if (!local->ops->wake_tx_queue && local->hw.wiphy->tx_queue_len)
+-                      ndev->tx_queue_len = local->hw.wiphy->tx_queue_len;
+-
+               dev_net_set(ndev, wiphy_net(local->hw.wiphy));
+               ndev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -630,7 +630,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
+       if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config ||
+                   !ops->add_interface || !ops->remove_interface ||
+-                  !ops->configure_filter))
++                  !ops->configure_filter || !ops->wake_tx_queue))
+               return NULL;
+       if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove)))
+@@ -719,9 +719,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
+       if (!ops->set_key)
+               wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+-      if (ops->wake_tx_queue)
+-              wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_TXQS);
+-
++      wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_TXQS);
+       wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_RRM);
+       wiphy->bss_priv_size = sizeof(struct ieee80211_bss);
+@@ -834,10 +832,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
+               atomic_set(&local->agg_queue_stop[i], 0);
+       }
+       tasklet_setup(&local->tx_pending_tasklet, ieee80211_tx_pending);
+-
+-      if (ops->wake_tx_queue)
+-              tasklet_setup(&local->wake_txqs_tasklet, ieee80211_wake_txqs);
+-
++      tasklet_setup(&local->wake_txqs_tasklet, ieee80211_wake_txqs);
+       tasklet_setup(&local->tasklet, ieee80211_tasklet_handler);
+       skb_queue_head_init(&local->skb_queue);
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -1571,9 +1571,6 @@ static void sta_ps_start(struct sta_info
+       ieee80211_clear_fast_xmit(sta);
+-      if (!sta->sta.txq[0])
+-              return;
+-
+       for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
+               struct ieee80211_txq *txq = sta->sta.txq[tid];
+               struct txq_info *txqi = to_txq_info(txq);
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -140,17 +140,15 @@ static void __cleanup_single_sta(struct
+               atomic_dec(&ps->num_sta_ps);
+       }
+-      if (sta->sta.txq[0]) {
+-              for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
+-                      struct txq_info *txqi;
++      for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
++              struct txq_info *txqi;
+-                      if (!sta->sta.txq[i])
+-                              continue;
++              if (!sta->sta.txq[i])
++                      continue;
+-                      txqi = to_txq_info(sta->sta.txq[i]);
++              txqi = to_txq_info(sta->sta.txq[i]);
+-                      ieee80211_txq_purge(local, txqi);
+-              }
++              ieee80211_txq_purge(local, txqi);
+       }
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+@@ -425,8 +423,7 @@ void sta_info_free(struct ieee80211_loca
+       sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
+-      if (sta->sta.txq[0])
+-              kfree(to_txq_info(sta->sta.txq[0]));
++      kfree(to_txq_info(sta->sta.txq[0]));
+       kfree(rcu_dereference_raw(sta->sta.rates));
+ #ifdef CPTCFG_MAC80211_MESH
+       kfree(sta->mesh);
+@@ -527,6 +524,8 @@ __sta_info_alloc(struct ieee80211_sub_if
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_hw *hw = &local->hw;
+       struct sta_info *sta;
++      void *txq_data;
++      int size;
+       int i;
+       sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp);
+@@ -597,21 +596,18 @@ __sta_info_alloc(struct ieee80211_sub_if
+       sta->last_connected = ktime_get_seconds();
+-      if (local->ops->wake_tx_queue) {
+-              void *txq_data;
+-              int size = sizeof(struct txq_info) +
+-                         ALIGN(hw->txq_data_size, sizeof(void *));
++      size = sizeof(struct txq_info) +
++             ALIGN(hw->txq_data_size, sizeof(void *));
+-              txq_data = kcalloc(ARRAY_SIZE(sta->sta.txq), size, gfp);
+-              if (!txq_data)
+-                      goto free;
++      txq_data = kcalloc(ARRAY_SIZE(sta->sta.txq), size, gfp);
++      if (!txq_data)
++              goto free;
+-              for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
+-                      struct txq_info *txq = txq_data + i * size;
++      for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
++              struct txq_info *txq = txq_data + i * size;
+-                      /* might not do anything for the bufferable MMPDU TXQ */
+-                      ieee80211_txq_init(sdata, sta, txq, i);
+-              }
++              /* might not do anything for the (bufferable) MMPDU TXQ */
++              ieee80211_txq_init(sdata, sta, txq, i);
+       }
+       if (sta_prepare_rate_control(local, sta, gfp))
+@@ -685,8 +681,7 @@ __sta_info_alloc(struct ieee80211_sub_if
+       return sta;
+ free_txq:
+-      if (sta->sta.txq[0])
+-              kfree(to_txq_info(sta->sta.txq[0]));
++      kfree(to_txq_info(sta->sta.txq[0]));
+ free:
+       sta_info_free_link(&sta->deflink);
+ #ifdef CPTCFG_MAC80211_MESH
+@@ -1959,9 +1954,6 @@ ieee80211_sta_ps_deliver_response(struct
+                * TIM recalculation.
+                */
+-              if (!sta->sta.txq[0])
+-                      return;
+-
+               for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
+                       if (!sta->sta.txq[tid] ||
+                           !(driver_release_tids & BIT(tid)) ||
+@@ -2446,7 +2438,7 @@ static void sta_set_tidstats(struct sta_
+               tidstats->tx_msdu_failed = sta->deflink.status_stats.msdu_failed[tid];
+       }
+-      if (local->ops->wake_tx_queue && tid < IEEE80211_NUM_TIDS) {
++      if (tid < IEEE80211_NUM_TIDS) {
+               spin_lock_bh(&local->fq.lock);
+               rcu_read_lock();
+@@ -2774,9 +2766,6 @@ unsigned long ieee80211_sta_last_active(
+ static void sta_update_codel_params(struct sta_info *sta, u32 thr)
+ {
+-      if (!sta->sdata->local->ops->wake_tx_queue)
+-              return;
+-
+       if (thr && thr < STA_SLOW_THRESHOLD * sta->local->num_sta) {
+               sta->cparams.target = MS2TIME(50);
+               sta->cparams.interval = MS2TIME(300);
+--- a/net/mac80211/tdls.c
++++ b/net/mac80211/tdls.c
+@@ -1016,7 +1016,6 @@ ieee80211_tdls_prep_mgmt_packet(struct w
+               skb->priority = 256 + 5;
+               break;
+       }
+-      skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
+       /*
+        * Set the WLAN_TDLS_TEARDOWN flag to indicate a teardown in progress.
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -1599,9 +1599,6 @@ int ieee80211_txq_setup_flows(struct iee
+       bool supp_vht = false;
+       enum nl80211_band band;
+-      if (!local->ops->wake_tx_queue)
+-              return 0;
+-
+       ret = fq_init(fq, 4096);
+       if (ret)
+               return ret;
+@@ -1649,9 +1646,6 @@ void ieee80211_txq_teardown_flows(struct
+ {
+       struct fq *fq = &local->fq;
+-      if (!local->ops->wake_tx_queue)
+-              return;
+-
+       kfree(local->cvars);
+       local->cvars = NULL;
+@@ -1668,8 +1662,7 @@ static bool ieee80211_queue_skb(struct i
+       struct ieee80211_vif *vif;
+       struct txq_info *txqi;
+-      if (!local->ops->wake_tx_queue ||
+-          sdata->vif.type == NL80211_IFTYPE_MONITOR)
++      if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+               return false;
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+@@ -4185,12 +4178,7 @@ void __ieee80211_subif_start_xmit(struct
+       if (IS_ERR(sta))
+               sta = NULL;
+-      if (local->ops->wake_tx_queue) {
+-              u16 queue = __ieee80211_select_queue(sdata, sta, skb);
+-              skb_set_queue_mapping(skb, queue);
+-              skb_get_hash(skb);
+-      }
+-
++      skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb));
+       ieee80211_aggr_check(sdata, sta, skb);
+       sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
+@@ -4501,11 +4489,7 @@ static void ieee80211_8023_xmit(struct i
+       struct tid_ampdu_tx *tid_tx;
+       u8 tid;
+-      if (local->ops->wake_tx_queue) {
+-              u16 queue = __ieee80211_select_queue(sdata, sta, skb);
+-              skb_set_queue_mapping(skb, queue);
+-              skb_get_hash(skb);
+-      }
++      skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb));
+       if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
+           test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
+@@ -4759,9 +4743,6 @@ void ieee80211_tx_pending(struct tasklet
+                       if (!txok)
+                               break;
+               }
+-
+-              if (skb_queue_empty(&local->pending[i]))
+-                      ieee80211_propagate_queue_wake(local, i);
+       }
+       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+@@ -5954,10 +5935,9 @@ int ieee80211_tx_control_port(struct wip
+       }
+       if (!IS_ERR(sta)) {
+-              u16 queue = __ieee80211_select_queue(sdata, sta, skb);
++              u16 queue = ieee80211_select_queue(sdata, sta, skb);
+               skb_set_queue_mapping(skb, queue);
+-              skb_get_hash(skb);
+               /*
+                * for MLO STA, the SA should be the AP MLD address, but
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -446,39 +446,6 @@ void ieee80211_wake_txqs(struct tasklet_
+       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+ }
+-void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
+-{
+-      struct ieee80211_sub_if_data *sdata;
+-      int n_acs = IEEE80211_NUM_ACS;
+-
+-      if (local->ops->wake_tx_queue)
+-              return;
+-
+-      if (local->hw.queues < IEEE80211_NUM_ACS)
+-              n_acs = 1;
+-
+-      list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+-              int ac;
+-
+-              if (!sdata->dev)
+-                      continue;
+-
+-              if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE &&
+-                  local->queue_stop_reasons[sdata->vif.cab_queue] != 0)
+-                      continue;
+-
+-              for (ac = 0; ac < n_acs; ac++) {
+-                      int ac_queue = sdata->vif.hw_queue[ac];
+-
+-                      if (ac_queue == queue ||
+-                          (sdata->vif.cab_queue == queue &&
+-                           local->queue_stop_reasons[ac_queue] == 0 &&
+-                           skb_queue_empty(&local->pending[ac_queue])))
+-                              netif_wake_subqueue(sdata->dev, ac);
+-              }
+-      }
+-}
+-
+ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
+                                  enum queue_stop_reason reason,
+                                  bool refcounted,
+@@ -509,11 +476,7 @@ static void __ieee80211_wake_queue(struc
+               /* someone still has this queue stopped */
+               return;
+-      if (skb_queue_empty(&local->pending[queue])) {
+-              rcu_read_lock();
+-              ieee80211_propagate_queue_wake(local, queue);
+-              rcu_read_unlock();
+-      } else
++      if (!skb_queue_empty(&local->pending[queue]))
+               tasklet_schedule(&local->tx_pending_tasklet);
+       /*
+@@ -523,12 +486,10 @@ static void __ieee80211_wake_queue(struc
+        * release someone's lock, but it is fine because all the callers of
+        * __ieee80211_wake_queue call it right before releasing the lock.
+        */
+-      if (local->ops->wake_tx_queue) {
+-              if (reason == IEEE80211_QUEUE_STOP_REASON_DRIVER)
+-                      tasklet_schedule(&local->wake_txqs_tasklet);
+-              else
+-                      _ieee80211_wake_txqs(local, flags);
+-      }
++      if (reason == IEEE80211_QUEUE_STOP_REASON_DRIVER)
++              tasklet_schedule(&local->wake_txqs_tasklet);
++      else
++              _ieee80211_wake_txqs(local, flags);
+ }
+ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
+@@ -585,10 +546,6 @@ static void __ieee80211_stop_queue(struc
+               for (ac = 0; ac < n_acs; ac++) {
+                       if (sdata->vif.hw_queue[ac] == queue ||
+                           sdata->vif.cab_queue == queue) {
+-                              if (!local->ops->wake_tx_queue) {
+-                                      netif_stop_subqueue(sdata->dev, ac);
+-                                      continue;
+-                              }
+                               spin_lock(&local->fq.lock);
+                               sdata->vif.txqs_stopped[ac] = true;
+                               spin_unlock(&local->fq.lock);
+--- a/net/mac80211/wme.c
++++ b/net/mac80211/wme.c
+@@ -122,6 +122,9 @@ u16 ieee80211_select_queue_80211(struct
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       u8 *p;
++      /* Ensure hash is set prior to potential SW encryption */
++      skb_get_hash(skb);
++
+       if ((info->control.flags & IEEE80211_TX_CTRL_DONT_REORDER) ||
+           local->hw.queues < IEEE80211_NUM_ACS)
+               return 0;
+@@ -141,12 +144,15 @@ u16 ieee80211_select_queue_80211(struct
+       return ieee80211_downgrade_queue(sdata, NULL, skb);
+ }
+-u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
+-                           struct sta_info *sta, struct sk_buff *skb)
++u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
++                         struct sta_info *sta, struct sk_buff *skb)
+ {
+       struct mac80211_qos_map *qos_map;
+       bool qos;
++      /* Ensure hash is set prior to potential SW encryption */
++      skb_get_hash(skb);
++
+       /* all mesh/ocb stations are required to support WME */
+       if (sta && (sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
+                   sdata->vif.type == NL80211_IFTYPE_OCB))
+@@ -176,59 +182,6 @@ u16 __ieee80211_select_queue(struct ieee
+       return ieee80211_downgrade_queue(sdata, sta, skb);
+ }
+-
+-/* Indicate which queue to use. */
+-u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
+-                         struct sk_buff *skb)
+-{
+-      struct ieee80211_local *local = sdata->local;
+-      struct sta_info *sta = NULL;
+-      const u8 *ra = NULL;
+-      u16 ret;
+-
+-      /* when using iTXQ, we can do this later */
+-      if (local->ops->wake_tx_queue)
+-              return 0;
+-
+-      if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
+-              skb->priority = 0; /* required for correct WPA/11i MIC */
+-              return 0;
+-      }
+-
+-      rcu_read_lock();
+-      switch (sdata->vif.type) {
+-      case NL80211_IFTYPE_AP_VLAN:
+-              sta = rcu_dereference(sdata->u.vlan.sta);
+-              if (sta)
+-                      break;
+-              fallthrough;
+-      case NL80211_IFTYPE_AP:
+-              ra = skb->data;
+-              break;
+-      case NL80211_IFTYPE_STATION:
+-              /* might be a TDLS station */
+-              sta = sta_info_get(sdata, skb->data);
+-              if (sta)
+-                      break;
+-
+-              ra = sdata->deflink.u.mgd.bssid;
+-              break;
+-      case NL80211_IFTYPE_ADHOC:
+-              ra = skb->data;
+-              break;
+-      default:
+-              break;
+-      }
+-
+-      if (!sta && ra && !is_multicast_ether_addr(ra))
+-              sta = sta_info_get(sdata, ra);
+-
+-      ret = __ieee80211_select_queue(sdata, sta, skb);
+-
+-      rcu_read_unlock();
+-      return ret;
+-}
+-
+ /**
+  * ieee80211_set_qos_hdr - Fill in the QoS header if there is one.
+  *
+--- a/net/mac80211/wme.h
++++ b/net/mac80211/wme.h
+@@ -13,10 +13,8 @@
+ u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
+                                struct sk_buff *skb,
+                                struct ieee80211_hdr *hdr);
+-u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
+-                           struct sta_info *sta, struct sk_buff *skb);
+ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
+-                         struct sk_buff *skb);
++                         struct sta_info *sta, struct sk_buff *skb);
+ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
+                          struct sk_buff *skb);
diff --git a/package/kernel/mac80211/patches/subsys/306-03-wifi-mac80211-Drop-support-for-TX-push-path.patch b/package/kernel/mac80211/patches/subsys/306-03-wifi-mac80211-Drop-support-for-TX-push-path.patch
deleted file mode 100644 (file)
index 9d58345..0000000
+++ /dev/null
@@ -1,655 +0,0 @@
-From: Alexander Wetzel <alexander@wetzel-home.de>
-Date: Sun, 9 Oct 2022 18:30:40 +0200
-Subject: [PATCH] wifi: mac80211: Drop support for TX push path
-
-All drivers are now using mac80211 internal queues (iTXQs).
-Drop mac80211 internal support for the old push path.
-
-Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -4339,9 +4339,6 @@ static int ieee80211_get_txq_stats(struc
-       struct ieee80211_sub_if_data *sdata;
-       int ret = 0;
--      if (!local->ops->wake_tx_queue)
--              return 1;
--
-       spin_lock_bh(&local->fq.lock);
-       rcu_read_lock();
---- a/net/mac80211/debugfs.c
-+++ b/net/mac80211/debugfs.c
-@@ -663,9 +663,7 @@ void debugfs_hw_add(struct ieee80211_loc
-       DEBUGFS_ADD_MODE(force_tx_status, 0600);
-       DEBUGFS_ADD_MODE(aql_enable, 0600);
-       DEBUGFS_ADD(aql_pending);
--
--      if (local->ops->wake_tx_queue)
--              DEBUGFS_ADD_MODE(aqm, 0600);
-+      DEBUGFS_ADD_MODE(aqm, 0600);
-       DEBUGFS_ADD_MODE(airtime_flags, 0600);
---- a/net/mac80211/debugfs_netdev.c
-+++ b/net/mac80211/debugfs_netdev.c
-@@ -677,8 +677,7 @@ static void add_common_files(struct ieee
-       DEBUGFS_ADD(rc_rateidx_vht_mcs_mask_5ghz);
-       DEBUGFS_ADD(hw_queues);
--      if (sdata->local->ops->wake_tx_queue &&
--          sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
-+      if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
-           sdata->vif.type != NL80211_IFTYPE_NAN)
-               DEBUGFS_ADD(aqm);
- }
---- a/net/mac80211/debugfs_sta.c
-+++ b/net/mac80211/debugfs_sta.c
-@@ -1056,10 +1056,8 @@ void ieee80211_sta_debugfs_add(struct st
-       DEBUGFS_ADD_COUNTER(rx_fragments, deflink.rx_stats.fragments);
-       DEBUGFS_ADD_COUNTER(tx_filtered, deflink.status_stats.filtered);
--      if (local->ops->wake_tx_queue) {
--              DEBUGFS_ADD(aqm);
--              DEBUGFS_ADD(airtime);
--      }
-+      DEBUGFS_ADD(aqm);
-+      DEBUGFS_ADD(airtime);
-       if (wiphy_ext_feature_isset(local->hw.wiphy,
-                                   NL80211_EXT_FEATURE_AQL))
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -2290,7 +2290,6 @@ void ieee80211_wake_queue_by_reason(stru
- void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
-                                   enum queue_stop_reason reason,
-                                   bool refcounted);
--void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue);
- void ieee80211_add_pending_skb(struct ieee80211_local *local,
-                              struct sk_buff *skb);
- void ieee80211_add_pending_skbs(struct ieee80211_local *local,
---- a/net/mac80211/iface.c
-+++ b/net/mac80211/iface.c
-@@ -458,12 +458,6 @@ static void ieee80211_do_stop(struct iee
-       if (cancel_scan)
-               ieee80211_scan_cancel(local);
--      /*
--       * Stop TX on this interface first.
--       */
--      if (!local->ops->wake_tx_queue && sdata->dev)
--              netif_tx_stop_all_queues(sdata->dev);
--
-       ieee80211_roc_purge(local, sdata);
-       switch (sdata->vif.type) {
-@@ -811,13 +805,6 @@ static void ieee80211_uninit(struct net_
-       ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev));
- }
--static u16 ieee80211_netdev_select_queue(struct net_device *dev,
--                                       struct sk_buff *skb,
--                                       struct net_device *sb_dev)
--{
--      return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
--}
--
- static void
- ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
- {
-@@ -831,7 +818,6 @@ static const struct net_device_ops ieee8
-       .ndo_start_xmit         = ieee80211_subif_start_xmit,
-       .ndo_set_rx_mode        = ieee80211_set_multicast_list,
-       .ndo_set_mac_address    = ieee80211_change_mac,
--      .ndo_select_queue       = ieee80211_netdev_select_queue,
-       .ndo_get_stats64        = ieee80211_get_stats64,
- };
-@@ -939,7 +925,6 @@ static const struct net_device_ops ieee8
-       .ndo_start_xmit         = ieee80211_subif_start_xmit_8023,
-       .ndo_set_rx_mode        = ieee80211_set_multicast_list,
-       .ndo_set_mac_address    = ieee80211_change_mac,
--      .ndo_select_queue       = ieee80211_netdev_select_queue,
-       .ndo_get_stats64        = ieee80211_get_stats64,
-       .ndo_fill_forward_path  = ieee80211_netdev_fill_forward_path,
- };
-@@ -1441,35 +1426,6 @@ int ieee80211_do_open(struct wireless_de
-       ieee80211_recalc_ps(local);
--      if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
--          sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
--          local->ops->wake_tx_queue) {
--              /* XXX: for AP_VLAN, actually track AP queues */
--              if (dev)
--                      netif_tx_start_all_queues(dev);
--      } else if (dev) {
--              unsigned long flags;
--              int n_acs = IEEE80211_NUM_ACS;
--              int ac;
--
--              if (local->hw.queues < IEEE80211_NUM_ACS)
--                      n_acs = 1;
--
--              spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
--              if (sdata->vif.cab_queue == IEEE80211_INVAL_HW_QUEUE ||
--                  (local->queue_stop_reasons[sdata->vif.cab_queue] == 0 &&
--                   skb_queue_empty(&local->pending[sdata->vif.cab_queue]))) {
--                      for (ac = 0; ac < n_acs; ac++) {
--                              int ac_queue = sdata->vif.hw_queue[ac];
--
--                              if (local->queue_stop_reasons[ac_queue] == 0 &&
--                                  skb_queue_empty(&local->pending[ac_queue]))
--                                      netif_start_subqueue(dev, ac);
--                      }
--              }
--              spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
--      }
--
-       set_bit(SDATA_STATE_RUNNING, &sdata->state);
-       return 0;
-@@ -1499,17 +1455,12 @@ static void ieee80211_if_setup(struct ne
- {
-       ether_setup(dev);
-       dev->priv_flags &= ~IFF_TX_SKB_SHARING;
-+      dev->priv_flags |= IFF_NO_QUEUE;
-       dev->netdev_ops = &ieee80211_dataif_ops;
-       dev->needs_free_netdev = true;
-       dev->priv_destructor = ieee80211_if_free;
- }
--static void ieee80211_if_setup_no_queue(struct net_device *dev)
--{
--      ieee80211_if_setup(dev);
--      dev->priv_flags |= IFF_NO_QUEUE;
--}
--
- static void ieee80211_iface_process_skb(struct ieee80211_local *local,
-                                       struct ieee80211_sub_if_data *sdata,
-                                       struct sk_buff *skb)
-@@ -2094,9 +2045,7 @@ int ieee80211_if_add(struct ieee80211_lo
-       struct net_device *ndev = NULL;
-       struct ieee80211_sub_if_data *sdata = NULL;
-       struct txq_info *txqi;
--      void (*if_setup)(struct net_device *dev);
-       int ret, i;
--      int txqs = 1;
-       ASSERT_RTNL();
-@@ -2119,30 +2068,18 @@ int ieee80211_if_add(struct ieee80211_lo
-                                sizeof(void *));
-               int txq_size = 0;
--              if (local->ops->wake_tx_queue &&
--                  type != NL80211_IFTYPE_AP_VLAN &&
-+              if (type != NL80211_IFTYPE_AP_VLAN &&
-                   (type != NL80211_IFTYPE_MONITOR ||
-                    (params->flags & MONITOR_FLAG_ACTIVE)))
-                       txq_size += sizeof(struct txq_info) +
-                                   local->hw.txq_data_size;
--              if (local->ops->wake_tx_queue) {
--                      if_setup = ieee80211_if_setup_no_queue;
--              } else {
--                      if_setup = ieee80211_if_setup;
--                      if (local->hw.queues >= IEEE80211_NUM_ACS)
--                              txqs = IEEE80211_NUM_ACS;
--              }
--
-               ndev = alloc_netdev_mqs(size + txq_size,
-                                       name, name_assign_type,
--                                      if_setup, txqs, 1);
-+                                      ieee80211_if_setup, 1, 1);
-               if (!ndev)
-                       return -ENOMEM;
--              if (!local->ops->wake_tx_queue && local->hw.wiphy->tx_queue_len)
--                      ndev->tx_queue_len = local->hw.wiphy->tx_queue_len;
--
-               dev_net_set(ndev, wiphy_net(local->hw.wiphy));
-               ndev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -630,7 +630,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
-       if (WARN_ON(!ops->tx || !ops->start || !ops->stop || !ops->config ||
-                   !ops->add_interface || !ops->remove_interface ||
--                  !ops->configure_filter))
-+                  !ops->configure_filter || !ops->wake_tx_queue))
-               return NULL;
-       if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove)))
-@@ -719,9 +719,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
-       if (!ops->set_key)
-               wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
--      if (ops->wake_tx_queue)
--              wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_TXQS);
--
-+      wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_TXQS);
-       wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_RRM);
-       wiphy->bss_priv_size = sizeof(struct ieee80211_bss);
-@@ -834,10 +832,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
-               atomic_set(&local->agg_queue_stop[i], 0);
-       }
-       tasklet_setup(&local->tx_pending_tasklet, ieee80211_tx_pending);
--
--      if (ops->wake_tx_queue)
--              tasklet_setup(&local->wake_txqs_tasklet, ieee80211_wake_txqs);
--
-+      tasklet_setup(&local->wake_txqs_tasklet, ieee80211_wake_txqs);
-       tasklet_setup(&local->tasklet, ieee80211_tasklet_handler);
-       skb_queue_head_init(&local->skb_queue);
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -1571,9 +1571,6 @@ static void sta_ps_start(struct sta_info
-       ieee80211_clear_fast_xmit(sta);
--      if (!sta->sta.txq[0])
--              return;
--
-       for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
-               struct ieee80211_txq *txq = sta->sta.txq[tid];
-               struct txq_info *txqi = to_txq_info(txq);
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -140,17 +140,15 @@ static void __cleanup_single_sta(struct
-               atomic_dec(&ps->num_sta_ps);
-       }
--      if (sta->sta.txq[0]) {
--              for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
--                      struct txq_info *txqi;
-+      for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
-+              struct txq_info *txqi;
--                      if (!sta->sta.txq[i])
--                              continue;
-+              if (!sta->sta.txq[i])
-+                      continue;
--                      txqi = to_txq_info(sta->sta.txq[i]);
-+              txqi = to_txq_info(sta->sta.txq[i]);
--                      ieee80211_txq_purge(local, txqi);
--              }
-+              ieee80211_txq_purge(local, txqi);
-       }
-       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-@@ -425,8 +423,7 @@ void sta_info_free(struct ieee80211_loca
-       sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
--      if (sta->sta.txq[0])
--              kfree(to_txq_info(sta->sta.txq[0]));
-+      kfree(to_txq_info(sta->sta.txq[0]));
-       kfree(rcu_dereference_raw(sta->sta.rates));
- #ifdef CPTCFG_MAC80211_MESH
-       kfree(sta->mesh);
-@@ -527,6 +524,8 @@ __sta_info_alloc(struct ieee80211_sub_if
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_hw *hw = &local->hw;
-       struct sta_info *sta;
-+      void *txq_data;
-+      int size;
-       int i;
-       sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp);
-@@ -597,21 +596,18 @@ __sta_info_alloc(struct ieee80211_sub_if
-       sta->last_connected = ktime_get_seconds();
--      if (local->ops->wake_tx_queue) {
--              void *txq_data;
--              int size = sizeof(struct txq_info) +
--                         ALIGN(hw->txq_data_size, sizeof(void *));
-+      size = sizeof(struct txq_info) +
-+             ALIGN(hw->txq_data_size, sizeof(void *));
--              txq_data = kcalloc(ARRAY_SIZE(sta->sta.txq), size, gfp);
--              if (!txq_data)
--                      goto free;
-+      txq_data = kcalloc(ARRAY_SIZE(sta->sta.txq), size, gfp);
-+      if (!txq_data)
-+              goto free;
--              for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
--                      struct txq_info *txq = txq_data + i * size;
-+      for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
-+              struct txq_info *txq = txq_data + i * size;
--                      /* might not do anything for the bufferable MMPDU TXQ */
--                      ieee80211_txq_init(sdata, sta, txq, i);
--              }
-+              /* might not do anything for the (bufferable) MMPDU TXQ */
-+              ieee80211_txq_init(sdata, sta, txq, i);
-       }
-       if (sta_prepare_rate_control(local, sta, gfp))
-@@ -685,8 +681,7 @@ __sta_info_alloc(struct ieee80211_sub_if
-       return sta;
- free_txq:
--      if (sta->sta.txq[0])
--              kfree(to_txq_info(sta->sta.txq[0]));
-+      kfree(to_txq_info(sta->sta.txq[0]));
- free:
-       sta_info_free_link(&sta->deflink);
- #ifdef CPTCFG_MAC80211_MESH
-@@ -1959,9 +1954,6 @@ ieee80211_sta_ps_deliver_response(struct
-                * TIM recalculation.
-                */
--              if (!sta->sta.txq[0])
--                      return;
--
-               for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) {
-                       if (!sta->sta.txq[tid] ||
-                           !(driver_release_tids & BIT(tid)) ||
-@@ -2446,7 +2438,7 @@ static void sta_set_tidstats(struct sta_
-               tidstats->tx_msdu_failed = sta->deflink.status_stats.msdu_failed[tid];
-       }
--      if (local->ops->wake_tx_queue && tid < IEEE80211_NUM_TIDS) {
-+      if (tid < IEEE80211_NUM_TIDS) {
-               spin_lock_bh(&local->fq.lock);
-               rcu_read_lock();
-@@ -2774,9 +2766,6 @@ unsigned long ieee80211_sta_last_active(
- static void sta_update_codel_params(struct sta_info *sta, u32 thr)
- {
--      if (!sta->sdata->local->ops->wake_tx_queue)
--              return;
--
-       if (thr && thr < STA_SLOW_THRESHOLD * sta->local->num_sta) {
-               sta->cparams.target = MS2TIME(50);
-               sta->cparams.interval = MS2TIME(300);
---- a/net/mac80211/tdls.c
-+++ b/net/mac80211/tdls.c
-@@ -1016,7 +1016,6 @@ ieee80211_tdls_prep_mgmt_packet(struct w
-               skb->priority = 256 + 5;
-               break;
-       }
--      skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
-       /*
-        * Set the WLAN_TDLS_TEARDOWN flag to indicate a teardown in progress.
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -1599,9 +1599,6 @@ int ieee80211_txq_setup_flows(struct iee
-       bool supp_vht = false;
-       enum nl80211_band band;
--      if (!local->ops->wake_tx_queue)
--              return 0;
--
-       ret = fq_init(fq, 4096);
-       if (ret)
-               return ret;
-@@ -1649,9 +1646,6 @@ void ieee80211_txq_teardown_flows(struct
- {
-       struct fq *fq = &local->fq;
--      if (!local->ops->wake_tx_queue)
--              return;
--
-       kfree(local->cvars);
-       local->cvars = NULL;
-@@ -1668,8 +1662,7 @@ static bool ieee80211_queue_skb(struct i
-       struct ieee80211_vif *vif;
-       struct txq_info *txqi;
--      if (!local->ops->wake_tx_queue ||
--          sdata->vif.type == NL80211_IFTYPE_MONITOR)
-+      if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
-               return false;
-       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-@@ -4185,12 +4178,7 @@ void __ieee80211_subif_start_xmit(struct
-       if (IS_ERR(sta))
-               sta = NULL;
--      if (local->ops->wake_tx_queue) {
--              u16 queue = __ieee80211_select_queue(sdata, sta, skb);
--              skb_set_queue_mapping(skb, queue);
--              skb_get_hash(skb);
--      }
--
-+      skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb));
-       ieee80211_aggr_check(sdata, sta, skb);
-       sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
-@@ -4501,11 +4489,7 @@ static void ieee80211_8023_xmit(struct i
-       struct tid_ampdu_tx *tid_tx;
-       u8 tid;
--      if (local->ops->wake_tx_queue) {
--              u16 queue = __ieee80211_select_queue(sdata, sta, skb);
--              skb_set_queue_mapping(skb, queue);
--              skb_get_hash(skb);
--      }
-+      skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb));
-       if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
-           test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
-@@ -4759,9 +4743,6 @@ void ieee80211_tx_pending(struct tasklet
-                       if (!txok)
-                               break;
-               }
--
--              if (skb_queue_empty(&local->pending[i]))
--                      ieee80211_propagate_queue_wake(local, i);
-       }
-       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-@@ -5954,10 +5935,9 @@ int ieee80211_tx_control_port(struct wip
-       }
-       if (!IS_ERR(sta)) {
--              u16 queue = __ieee80211_select_queue(sdata, sta, skb);
-+              u16 queue = ieee80211_select_queue(sdata, sta, skb);
-               skb_set_queue_mapping(skb, queue);
--              skb_get_hash(skb);
-               /*
-                * for MLO STA, the SA should be the AP MLD address, but
---- a/net/mac80211/util.c
-+++ b/net/mac80211/util.c
-@@ -446,39 +446,6 @@ void ieee80211_wake_txqs(struct tasklet_
-       spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
- }
--void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
--{
--      struct ieee80211_sub_if_data *sdata;
--      int n_acs = IEEE80211_NUM_ACS;
--
--      if (local->ops->wake_tx_queue)
--              return;
--
--      if (local->hw.queues < IEEE80211_NUM_ACS)
--              n_acs = 1;
--
--      list_for_each_entry_rcu(sdata, &local->interfaces, list) {
--              int ac;
--
--              if (!sdata->dev)
--                      continue;
--
--              if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE &&
--                  local->queue_stop_reasons[sdata->vif.cab_queue] != 0)
--                      continue;
--
--              for (ac = 0; ac < n_acs; ac++) {
--                      int ac_queue = sdata->vif.hw_queue[ac];
--
--                      if (ac_queue == queue ||
--                          (sdata->vif.cab_queue == queue &&
--                           local->queue_stop_reasons[ac_queue] == 0 &&
--                           skb_queue_empty(&local->pending[ac_queue])))
--                              netif_wake_subqueue(sdata->dev, ac);
--              }
--      }
--}
--
- static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
-                                  enum queue_stop_reason reason,
-                                  bool refcounted,
-@@ -509,11 +476,7 @@ static void __ieee80211_wake_queue(struc
-               /* someone still has this queue stopped */
-               return;
--      if (skb_queue_empty(&local->pending[queue])) {
--              rcu_read_lock();
--              ieee80211_propagate_queue_wake(local, queue);
--              rcu_read_unlock();
--      } else
-+      if (!skb_queue_empty(&local->pending[queue]))
-               tasklet_schedule(&local->tx_pending_tasklet);
-       /*
-@@ -523,12 +486,10 @@ static void __ieee80211_wake_queue(struc
-        * release someone's lock, but it is fine because all the callers of
-        * __ieee80211_wake_queue call it right before releasing the lock.
-        */
--      if (local->ops->wake_tx_queue) {
--              if (reason == IEEE80211_QUEUE_STOP_REASON_DRIVER)
--                      tasklet_schedule(&local->wake_txqs_tasklet);
--              else
--                      _ieee80211_wake_txqs(local, flags);
--      }
-+      if (reason == IEEE80211_QUEUE_STOP_REASON_DRIVER)
-+              tasklet_schedule(&local->wake_txqs_tasklet);
-+      else
-+              _ieee80211_wake_txqs(local, flags);
- }
- void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
-@@ -585,10 +546,6 @@ static void __ieee80211_stop_queue(struc
-               for (ac = 0; ac < n_acs; ac++) {
-                       if (sdata->vif.hw_queue[ac] == queue ||
-                           sdata->vif.cab_queue == queue) {
--                              if (!local->ops->wake_tx_queue) {
--                                      netif_stop_subqueue(sdata->dev, ac);
--                                      continue;
--                              }
-                               spin_lock(&local->fq.lock);
-                               sdata->vif.txqs_stopped[ac] = true;
-                               spin_unlock(&local->fq.lock);
---- a/net/mac80211/wme.c
-+++ b/net/mac80211/wme.c
-@@ -122,6 +122,9 @@ u16 ieee80211_select_queue_80211(struct
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       u8 *p;
-+      /* Ensure hash is set prior to potential SW encryption */
-+      skb_get_hash(skb);
-+
-       if ((info->control.flags & IEEE80211_TX_CTRL_DONT_REORDER) ||
-           local->hw.queues < IEEE80211_NUM_ACS)
-               return 0;
-@@ -141,12 +144,15 @@ u16 ieee80211_select_queue_80211(struct
-       return ieee80211_downgrade_queue(sdata, NULL, skb);
- }
--u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
--                           struct sta_info *sta, struct sk_buff *skb)
-+u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
-+                         struct sta_info *sta, struct sk_buff *skb)
- {
-       struct mac80211_qos_map *qos_map;
-       bool qos;
-+      /* Ensure hash is set prior to potential SW encryption */
-+      skb_get_hash(skb);
-+
-       /* all mesh/ocb stations are required to support WME */
-       if (sta && (sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
-                   sdata->vif.type == NL80211_IFTYPE_OCB))
-@@ -176,59 +182,6 @@ u16 __ieee80211_select_queue(struct ieee
-       return ieee80211_downgrade_queue(sdata, sta, skb);
- }
--
--/* Indicate which queue to use. */
--u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
--                         struct sk_buff *skb)
--{
--      struct ieee80211_local *local = sdata->local;
--      struct sta_info *sta = NULL;
--      const u8 *ra = NULL;
--      u16 ret;
--
--      /* when using iTXQ, we can do this later */
--      if (local->ops->wake_tx_queue)
--              return 0;
--
--      if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
--              skb->priority = 0; /* required for correct WPA/11i MIC */
--              return 0;
--      }
--
--      rcu_read_lock();
--      switch (sdata->vif.type) {
--      case NL80211_IFTYPE_AP_VLAN:
--              sta = rcu_dereference(sdata->u.vlan.sta);
--              if (sta)
--                      break;
--              fallthrough;
--      case NL80211_IFTYPE_AP:
--              ra = skb->data;
--              break;
--      case NL80211_IFTYPE_STATION:
--              /* might be a TDLS station */
--              sta = sta_info_get(sdata, skb->data);
--              if (sta)
--                      break;
--
--              ra = sdata->deflink.u.mgd.bssid;
--              break;
--      case NL80211_IFTYPE_ADHOC:
--              ra = skb->data;
--              break;
--      default:
--              break;
--      }
--
--      if (!sta && ra && !is_multicast_ether_addr(ra))
--              sta = sta_info_get(sdata, ra);
--
--      ret = __ieee80211_select_queue(sdata, sta, skb);
--
--      rcu_read_unlock();
--      return ret;
--}
--
- /**
-  * ieee80211_set_qos_hdr - Fill in the QoS header if there is one.
-  *
---- a/net/mac80211/wme.h
-+++ b/net/mac80211/wme.h
-@@ -13,10 +13,8 @@
- u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata,
-                                struct sk_buff *skb,
-                                struct ieee80211_hdr *hdr);
--u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
--                           struct sta_info *sta, struct sk_buff *skb);
- u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
--                         struct sk_buff *skb);
-+                         struct sta_info *sta, struct sk_buff *skb);
- void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
-                          struct sk_buff *skb);
diff --git a/package/kernel/mac80211/patches/subsys/306-04-v6.2-wifi-realtek-remove-duplicated-wake_tx_queue.patch b/package/kernel/mac80211/patches/subsys/306-04-v6.2-wifi-realtek-remove-duplicated-wake_tx_queue.patch
new file mode 100644 (file)
index 0000000..f0dfc75
--- /dev/null
@@ -0,0 +1,32 @@
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 10 Oct 2022 19:17:46 +0200
+Subject: [PATCH] wifi: realtek: remove duplicated wake_tx_queue
+
+By accident, the previous patch duplicated the initialization
+of the wake_tx_queue callback. Fix that by removing the new
+initializations.
+
+Fixes: a790cc3a4fad ("wifi: mac80211: add wake_tx_queue callback to drivers")
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
++++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
+@@ -896,7 +896,6 @@ static void rtw_ops_sta_rc_update(struct
+ const struct ieee80211_ops rtw_ops = {
+       .tx                     = rtw_ops_tx,
+-      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .wake_tx_queue          = rtw_ops_wake_tx_queue,
+       .start                  = rtw_ops_start,
+       .stop                   = rtw_ops_stop,
+--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
++++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
+@@ -918,7 +918,6 @@ static int rtw89_ops_set_tid_config(stru
+ const struct ieee80211_ops rtw89_ops = {
+       .tx                     = rtw89_ops_tx,
+-      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
+       .wake_tx_queue          = rtw89_ops_wake_tx_queue,
+       .start                  = rtw89_ops_start,
+       .stop                   = rtw89_ops_stop,
diff --git a/package/kernel/mac80211/patches/subsys/306-04-wifi-realtek-remove-duplicated-wake_tx_queue.patch b/package/kernel/mac80211/patches/subsys/306-04-wifi-realtek-remove-duplicated-wake_tx_queue.patch
deleted file mode 100644 (file)
index f0dfc75..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-From: Johannes Berg <johannes.berg@intel.com>
-Date: Mon, 10 Oct 2022 19:17:46 +0200
-Subject: [PATCH] wifi: realtek: remove duplicated wake_tx_queue
-
-By accident, the previous patch duplicated the initialization
-of the wake_tx_queue callback. Fix that by removing the new
-initializations.
-
-Fixes: a790cc3a4fad ("wifi: mac80211: add wake_tx_queue callback to drivers")
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/drivers/net/wireless/realtek/rtw88/mac80211.c
-+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
-@@ -896,7 +896,6 @@ static void rtw_ops_sta_rc_update(struct
- const struct ieee80211_ops rtw_ops = {
-       .tx                     = rtw_ops_tx,
--      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .wake_tx_queue          = rtw_ops_wake_tx_queue,
-       .start                  = rtw_ops_start,
-       .stop                   = rtw_ops_stop,
---- a/drivers/net/wireless/realtek/rtw89/mac80211.c
-+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
-@@ -918,7 +918,6 @@ static int rtw89_ops_set_tid_config(stru
- const struct ieee80211_ops rtw89_ops = {
-       .tx                     = rtw89_ops_tx,
--      .wake_tx_queue          = ieee80211_handle_wake_tx_queue,
-       .wake_tx_queue          = rtw89_ops_wake_tx_queue,
-       .start                  = rtw89_ops_start,
-       .stop                   = rtw89_ops_stop,
diff --git a/package/kernel/mac80211/patches/subsys/307-v6.2-wifi-mac80211-fix-initialization-of-rx-link-and-rx-l.patch b/package/kernel/mac80211/patches/subsys/307-v6.2-wifi-mac80211-fix-initialization-of-rx-link-and-rx-l.patch
new file mode 100644 (file)
index 0000000..0201eea
--- /dev/null
@@ -0,0 +1,410 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 13 Dec 2022 21:03:19 +0100
+Subject: [PATCH] wifi: mac80211: fix initialization of rx->link and
+ rx->link_sta
+
+There are some codepaths that do not initialize rx->link_sta properly. This
+causes a crash in places which assume that rx->link_sta is valid if rx->sta
+is valid.
+One known instance is triggered by __ieee80211_rx_h_amsdu being called from
+fast-rx.
+
+Since the initialization of rx->link and rx->link_sta is rather convoluted
+and duplicated in many places, clean it up by using a helper function to
+set it.
+
+Fixes: ccdde7c74ffd ("wifi: mac80211: properly implement MLO key handling")
+Fixes: b320d6c456ff ("wifi: mac80211: use correct rx link_sta instead of default")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -4067,6 +4067,58 @@ static void ieee80211_invoke_rx_handlers
+ #undef CALL_RXH
+ }
++static bool
++ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id)
++{
++      if (!sta->mlo)
++              return false;
++
++      return !!(sta->valid_links & BIT(link_id));
++}
++
++static bool ieee80211_rx_data_set_link(struct ieee80211_rx_data *rx,
++                                     u8 link_id)
++{
++      rx->link_id = link_id;
++      rx->link = rcu_dereference(rx->sdata->link[link_id]);
++
++      if (!rx->sta || !rx->sta->sta.mlo)
++              return rx->link;
++
++      if (!ieee80211_rx_is_valid_sta_link_id(&rx->sta->sta, link_id))
++              return false;
++
++      rx->link_sta = rcu_dereference(rx->sta->link[link_id]);
++
++      return rx->link && rx->link_sta;
++}
++
++static bool ieee80211_rx_data_set_sta(struct ieee80211_rx_data *rx,
++                                    struct ieee80211_sta *pubsta,
++                                    int link_id)
++{
++      struct sta_info *sta;
++
++      sta = container_of(pubsta, struct sta_info, sta);
++
++      rx->link_id = link_id;
++      rx->sta = sta;
++
++      if (sta) {
++              rx->local = sta->sdata->local;
++              if (!rx->sdata)
++                      rx->sdata = sta->sdata;
++              rx->link_sta = &sta->deflink;
++      }
++
++      if (link_id < 0)
++              rx->link = &rx->sdata->deflink;
++      else if (!ieee80211_rx_data_set_link(rx, link_id))
++              return false;
++
++      return true;
++}
++
+ /*
+  * This function makes calls into the RX path, therefore
+  * it has to be invoked under RCU read lock.
+@@ -4075,16 +4127,19 @@ void ieee80211_release_reorder_timeout(s
+ {
+       struct sk_buff_head frames;
+       struct ieee80211_rx_data rx = {
+-              .sta = sta,
+-              .sdata = sta->sdata,
+-              .local = sta->local,
+               /* This is OK -- must be QoS data frame */
+               .security_idx = tid,
+               .seqno_idx = tid,
+-              .link_id = -1,
+       };
+       struct tid_ampdu_rx *tid_agg_rx;
+-      u8 link_id;
++      int link_id = -1;
++
++      /* FIXME: statistics won't be right with this */
++      if (sta->sta.valid_links)
++              link_id = ffs(sta->sta.valid_links) - 1;
++
++      if (!ieee80211_rx_data_set_sta(&rx, &sta->sta, link_id))
++              return;
+       tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
+       if (!tid_agg_rx)
+@@ -4104,10 +4159,6 @@ void ieee80211_release_reorder_timeout(s
+               };
+               drv_event_callback(rx.local, rx.sdata, &event);
+       }
+-      /* FIXME: statistics won't be right with this */
+-      link_id = sta->sta.valid_links ? ffs(sta->sta.valid_links) - 1 : 0;
+-      rx.link = rcu_dereference(sta->sdata->link[link_id]);
+-      rx.link_sta = rcu_dereference(sta->link[link_id]);
+       ieee80211_rx_handlers(&rx, &frames);
+ }
+@@ -4123,7 +4174,6 @@ void ieee80211_mark_rx_ba_filtered_frame
+               /* This is OK -- must be QoS data frame */
+               .security_idx = tid,
+               .seqno_idx = tid,
+-              .link_id = -1,
+       };
+       int i, diff;
+@@ -4134,10 +4184,8 @@ void ieee80211_mark_rx_ba_filtered_frame
+       sta = container_of(pubsta, struct sta_info, sta);
+-      rx.sta = sta;
+-      rx.sdata = sta->sdata;
+-      rx.link = &rx.sdata->deflink;
+-      rx.local = sta->local;
++      if (!ieee80211_rx_data_set_sta(&rx, pubsta, -1))
++              return;
+       rcu_read_lock();
+       tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
+@@ -4524,15 +4572,6 @@ void ieee80211_check_fast_rx_iface(struc
+       mutex_unlock(&local->sta_mtx);
+ }
+-static bool
+-ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id)
+-{
+-      if (!sta->mlo)
+-              return false;
+-
+-      return !!(sta->valid_links & BIT(link_id));
+-}
+-
+ static void ieee80211_rx_8023(struct ieee80211_rx_data *rx,
+                             struct ieee80211_fast_rx *fast_rx,
+                             int orig_len)
+@@ -4643,7 +4682,6 @@ static bool ieee80211_invoke_fast_rx(str
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+-      struct sta_info *sta = rx->sta;
+       int orig_len = skb->len;
+       int hdrlen = ieee80211_hdrlen(hdr->frame_control);
+       int snap_offs = hdrlen;
+@@ -4655,7 +4693,6 @@ static bool ieee80211_invoke_fast_rx(str
+               u8 da[ETH_ALEN];
+               u8 sa[ETH_ALEN];
+       } addrs __aligned(2);
+-      struct link_sta_info *link_sta;
+       struct ieee80211_sta_rx_stats *stats;
+       /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
+@@ -4758,18 +4795,10 @@ static bool ieee80211_invoke_fast_rx(str
+  drop:
+       dev_kfree_skb(skb);
+-      if (rx->link_id >= 0) {
+-              link_sta = rcu_dereference(sta->link[rx->link_id]);
+-              if (!link_sta)
+-                      return true;
+-      } else {
+-              link_sta = &sta->deflink;
+-      }
+-
+       if (fast_rx->uses_rss)
+-              stats = this_cpu_ptr(link_sta->pcpu_rx_stats);
++              stats = this_cpu_ptr(rx->link_sta->pcpu_rx_stats);
+       else
+-              stats = &link_sta->rx_stats;
++              stats = &rx->link_sta->rx_stats;
+       stats->dropped++;
+       return true;
+@@ -4787,8 +4816,8 @@ static bool ieee80211_prepare_and_rx_han
+       struct ieee80211_local *local = rx->local;
+       struct ieee80211_sub_if_data *sdata = rx->sdata;
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+-      struct link_sta_info *link_sta = NULL;
+-      struct ieee80211_link_data *link;
++      struct link_sta_info *link_sta = rx->link_sta;
++      struct ieee80211_link_data *link = rx->link;
+       rx->skb = skb;
+@@ -4810,35 +4839,6 @@ static bool ieee80211_prepare_and_rx_han
+       if (!ieee80211_accept_frame(rx))
+               return false;
+-      if (rx->link_id >= 0) {
+-              link = rcu_dereference(rx->sdata->link[rx->link_id]);
+-
+-              /* we might race link removal */
+-              if (!link)
+-                      return true;
+-              rx->link = link;
+-
+-              if (rx->sta) {
+-                      rx->link_sta =
+-                              rcu_dereference(rx->sta->link[rx->link_id]);
+-                      if (!rx->link_sta)
+-                              return true;
+-              }
+-      } else {
+-              if (rx->sta)
+-                      rx->link_sta = &rx->sta->deflink;
+-
+-              rx->link = &sdata->deflink;
+-      }
+-
+-      if (unlikely(!is_multicast_ether_addr(hdr->addr1) &&
+-                   rx->link_id >= 0 && rx->sta && rx->sta->sta.mlo)) {
+-              link_sta = rcu_dereference(rx->sta->link[rx->link_id]);
+-
+-              if (WARN_ON_ONCE(!link_sta))
+-                      return true;
+-      }
+-
+       if (!consume) {
+               struct skb_shared_hwtstamps *shwt;
+@@ -4858,7 +4858,7 @@ static bool ieee80211_prepare_and_rx_han
+               shwt->hwtstamp = skb_hwtstamps(skb)->hwtstamp;
+       }
+-      if (unlikely(link_sta)) {
++      if (unlikely(rx->sta && rx->sta->sta.mlo)) {
+               /* translate to MLD addresses */
+               if (ether_addr_equal(link->conf->addr, hdr->addr1))
+                       ether_addr_copy(hdr->addr1, rx->sdata->vif.addr);
+@@ -4888,6 +4888,7 @@ static void __ieee80211_rx_handle_8023(s
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+       struct ieee80211_fast_rx *fast_rx;
+       struct ieee80211_rx_data rx;
++      int link_id = -1;
+       memset(&rx, 0, sizeof(rx));
+       rx.skb = skb;
+@@ -4904,12 +4905,8 @@ static void __ieee80211_rx_handle_8023(s
+       if (!pubsta)
+               goto drop;
+-      rx.sta = container_of(pubsta, struct sta_info, sta);
+-      rx.sdata = rx.sta->sdata;
+-
+-      if (status->link_valid &&
+-          !ieee80211_rx_is_valid_sta_link_id(pubsta, status->link_id))
+-              goto drop;
++      if (status->link_valid)
++              link_id = status->link_id;
+       /*
+        * TODO: Should the frame be dropped if the right link_id is not
+@@ -4918,19 +4915,8 @@ static void __ieee80211_rx_handle_8023(s
+        * link_id is used only for stats purpose and updating the stats on
+        * the deflink is fine?
+        */
+-      if (status->link_valid)
+-              rx.link_id = status->link_id;
+-
+-      if (rx.link_id >= 0) {
+-              struct ieee80211_link_data *link;
+-
+-              link =  rcu_dereference(rx.sdata->link[rx.link_id]);
+-              if (!link)
+-                      goto drop;
+-              rx.link = link;
+-      } else {
+-              rx.link = &rx.sdata->deflink;
+-      }
++      if (!ieee80211_rx_data_set_sta(&rx, pubsta, link_id))
++              goto drop;
+       fast_rx = rcu_dereference(rx.sta->fast_rx);
+       if (!fast_rx)
+@@ -4948,6 +4934,8 @@ static bool ieee80211_rx_for_interface(s
+ {
+       struct link_sta_info *link_sta;
+       struct ieee80211_hdr *hdr = (void *)skb->data;
++      struct sta_info *sta;
++      int link_id = -1;
+       /*
+        * Look up link station first, in case there's a
+@@ -4957,24 +4945,19 @@ static bool ieee80211_rx_for_interface(s
+        */
+       link_sta = link_sta_info_get_bss(rx->sdata, hdr->addr2);
+       if (link_sta) {
+-              rx->sta = link_sta->sta;
+-              rx->link_id = link_sta->link_id;
++              sta = link_sta->sta;
++              link_id = link_sta->link_id;
+       } else {
+               struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+-              rx->sta = sta_info_get_bss(rx->sdata, hdr->addr2);
+-              if (rx->sta) {
+-                      if (status->link_valid &&
+-                          !ieee80211_rx_is_valid_sta_link_id(&rx->sta->sta,
+-                                                             status->link_id))
+-                              return false;
+-
+-                      rx->link_id = status->link_valid ? status->link_id : -1;
+-              } else {
+-                      rx->link_id = -1;
+-              }
++              sta = sta_info_get_bss(rx->sdata, hdr->addr2);
++              if (status->link_valid)
++                      link_id = status->link_id;
+       }
++      if (!ieee80211_rx_data_set_sta(rx, &sta->sta, link_id))
++              return false;
++
+       return ieee80211_prepare_and_rx_handle(rx, skb, consume);
+ }
+@@ -5033,19 +5016,15 @@ static void __ieee80211_rx_handle_packet
+       if (ieee80211_is_data(fc)) {
+               struct sta_info *sta, *prev_sta;
+-              u8 link_id = status->link_id;
++              int link_id = -1;
+-              if (pubsta) {
+-                      rx.sta = container_of(pubsta, struct sta_info, sta);
+-                      rx.sdata = rx.sta->sdata;
++              if (status->link_valid)
++                      link_id = status->link_id;
+-                      if (status->link_valid &&
+-                          !ieee80211_rx_is_valid_sta_link_id(pubsta, link_id))
++              if (pubsta) {
++                      if (!ieee80211_rx_data_set_sta(&rx, pubsta, link_id))
+                               goto out;
+-                      if (status->link_valid)
+-                              rx.link_id = status->link_id;
+-
+                       /*
+                        * In MLO connection, fetch the link_id using addr2
+                        * when the driver does not pass link_id in status.
+@@ -5063,7 +5042,7 @@ static void __ieee80211_rx_handle_packet
+                               if (!link_sta)
+                                       goto out;
+-                              rx.link_id = link_sta->link_id;
++                              ieee80211_rx_data_set_link(&rx, link_sta->link_id);
+                       }
+                       if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
+@@ -5079,30 +5058,27 @@ static void __ieee80211_rx_handle_packet
+                               continue;
+                       }
+-                      if ((status->link_valid &&
+-                           !ieee80211_rx_is_valid_sta_link_id(&prev_sta->sta,
+-                                                              link_id)) ||
+-                          (!status->link_valid && prev_sta->sta.mlo))
++                      rx.sdata = prev_sta->sdata;
++                      if (!ieee80211_rx_data_set_sta(&rx, &prev_sta->sta,
++                                                     link_id))
++                              goto out;
++
++                      if (!status->link_valid && prev_sta->sta.mlo)
+                               continue;
+-                      rx.link_id = status->link_valid ? link_id : -1;
+-                      rx.sta = prev_sta;
+-                      rx.sdata = prev_sta->sdata;
+                       ieee80211_prepare_and_rx_handle(&rx, skb, false);
+                       prev_sta = sta;
+               }
+               if (prev_sta) {
+-                      if ((status->link_valid &&
+-                           !ieee80211_rx_is_valid_sta_link_id(&prev_sta->sta,
+-                                                              link_id)) ||
+-                          (!status->link_valid && prev_sta->sta.mlo))
++                      rx.sdata = prev_sta->sdata;
++                      if (!ieee80211_rx_data_set_sta(&rx, &prev_sta->sta,
++                                                     link_id))
+                               goto out;
+-                      rx.link_id = status->link_valid ? link_id : -1;
+-                      rx.sta = prev_sta;
+-                      rx.sdata = prev_sta->sdata;
++                      if (!status->link_valid && prev_sta->sta.mlo)
++                              goto out;
+                       if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
+                               return;
diff --git a/package/kernel/mac80211/patches/subsys/307-wifi-mac80211-fix-initialization-of-rx-link-and-rx-l.patch b/package/kernel/mac80211/patches/subsys/307-wifi-mac80211-fix-initialization-of-rx-link-and-rx-l.patch
deleted file mode 100644 (file)
index 0201eea..0000000
+++ /dev/null
@@ -1,410 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Tue, 13 Dec 2022 21:03:19 +0100
-Subject: [PATCH] wifi: mac80211: fix initialization of rx->link and
- rx->link_sta
-
-There are some codepaths that do not initialize rx->link_sta properly. This
-causes a crash in places which assume that rx->link_sta is valid if rx->sta
-is valid.
-One known instance is triggered by __ieee80211_rx_h_amsdu being called from
-fast-rx.
-
-Since the initialization of rx->link and rx->link_sta is rather convoluted
-and duplicated in many places, clean it up by using a helper function to
-set it.
-
-Fixes: ccdde7c74ffd ("wifi: mac80211: properly implement MLO key handling")
-Fixes: b320d6c456ff ("wifi: mac80211: use correct rx link_sta instead of default")
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -4067,6 +4067,58 @@ static void ieee80211_invoke_rx_handlers
- #undef CALL_RXH
- }
-+static bool
-+ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id)
-+{
-+      if (!sta->mlo)
-+              return false;
-+
-+      return !!(sta->valid_links & BIT(link_id));
-+}
-+
-+static bool ieee80211_rx_data_set_link(struct ieee80211_rx_data *rx,
-+                                     u8 link_id)
-+{
-+      rx->link_id = link_id;
-+      rx->link = rcu_dereference(rx->sdata->link[link_id]);
-+
-+      if (!rx->sta || !rx->sta->sta.mlo)
-+              return rx->link;
-+
-+      if (!ieee80211_rx_is_valid_sta_link_id(&rx->sta->sta, link_id))
-+              return false;
-+
-+      rx->link_sta = rcu_dereference(rx->sta->link[link_id]);
-+
-+      return rx->link && rx->link_sta;
-+}
-+
-+static bool ieee80211_rx_data_set_sta(struct ieee80211_rx_data *rx,
-+                                    struct ieee80211_sta *pubsta,
-+                                    int link_id)
-+{
-+      struct sta_info *sta;
-+
-+      sta = container_of(pubsta, struct sta_info, sta);
-+
-+      rx->link_id = link_id;
-+      rx->sta = sta;
-+
-+      if (sta) {
-+              rx->local = sta->sdata->local;
-+              if (!rx->sdata)
-+                      rx->sdata = sta->sdata;
-+              rx->link_sta = &sta->deflink;
-+      }
-+
-+      if (link_id < 0)
-+              rx->link = &rx->sdata->deflink;
-+      else if (!ieee80211_rx_data_set_link(rx, link_id))
-+              return false;
-+
-+      return true;
-+}
-+
- /*
-  * This function makes calls into the RX path, therefore
-  * it has to be invoked under RCU read lock.
-@@ -4075,16 +4127,19 @@ void ieee80211_release_reorder_timeout(s
- {
-       struct sk_buff_head frames;
-       struct ieee80211_rx_data rx = {
--              .sta = sta,
--              .sdata = sta->sdata,
--              .local = sta->local,
-               /* This is OK -- must be QoS data frame */
-               .security_idx = tid,
-               .seqno_idx = tid,
--              .link_id = -1,
-       };
-       struct tid_ampdu_rx *tid_agg_rx;
--      u8 link_id;
-+      int link_id = -1;
-+
-+      /* FIXME: statistics won't be right with this */
-+      if (sta->sta.valid_links)
-+              link_id = ffs(sta->sta.valid_links) - 1;
-+
-+      if (!ieee80211_rx_data_set_sta(&rx, &sta->sta, link_id))
-+              return;
-       tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
-       if (!tid_agg_rx)
-@@ -4104,10 +4159,6 @@ void ieee80211_release_reorder_timeout(s
-               };
-               drv_event_callback(rx.local, rx.sdata, &event);
-       }
--      /* FIXME: statistics won't be right with this */
--      link_id = sta->sta.valid_links ? ffs(sta->sta.valid_links) - 1 : 0;
--      rx.link = rcu_dereference(sta->sdata->link[link_id]);
--      rx.link_sta = rcu_dereference(sta->link[link_id]);
-       ieee80211_rx_handlers(&rx, &frames);
- }
-@@ -4123,7 +4174,6 @@ void ieee80211_mark_rx_ba_filtered_frame
-               /* This is OK -- must be QoS data frame */
-               .security_idx = tid,
-               .seqno_idx = tid,
--              .link_id = -1,
-       };
-       int i, diff;
-@@ -4134,10 +4184,8 @@ void ieee80211_mark_rx_ba_filtered_frame
-       sta = container_of(pubsta, struct sta_info, sta);
--      rx.sta = sta;
--      rx.sdata = sta->sdata;
--      rx.link = &rx.sdata->deflink;
--      rx.local = sta->local;
-+      if (!ieee80211_rx_data_set_sta(&rx, pubsta, -1))
-+              return;
-       rcu_read_lock();
-       tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
-@@ -4524,15 +4572,6 @@ void ieee80211_check_fast_rx_iface(struc
-       mutex_unlock(&local->sta_mtx);
- }
--static bool
--ieee80211_rx_is_valid_sta_link_id(struct ieee80211_sta *sta, u8 link_id)
--{
--      if (!sta->mlo)
--              return false;
--
--      return !!(sta->valid_links & BIT(link_id));
--}
--
- static void ieee80211_rx_8023(struct ieee80211_rx_data *rx,
-                             struct ieee80211_fast_rx *fast_rx,
-                             int orig_len)
-@@ -4643,7 +4682,6 @@ static bool ieee80211_invoke_fast_rx(str
-       struct sk_buff *skb = rx->skb;
-       struct ieee80211_hdr *hdr = (void *)skb->data;
-       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
--      struct sta_info *sta = rx->sta;
-       int orig_len = skb->len;
-       int hdrlen = ieee80211_hdrlen(hdr->frame_control);
-       int snap_offs = hdrlen;
-@@ -4655,7 +4693,6 @@ static bool ieee80211_invoke_fast_rx(str
-               u8 da[ETH_ALEN];
-               u8 sa[ETH_ALEN];
-       } addrs __aligned(2);
--      struct link_sta_info *link_sta;
-       struct ieee80211_sta_rx_stats *stats;
-       /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write
-@@ -4758,18 +4795,10 @@ static bool ieee80211_invoke_fast_rx(str
-  drop:
-       dev_kfree_skb(skb);
--      if (rx->link_id >= 0) {
--              link_sta = rcu_dereference(sta->link[rx->link_id]);
--              if (!link_sta)
--                      return true;
--      } else {
--              link_sta = &sta->deflink;
--      }
--
-       if (fast_rx->uses_rss)
--              stats = this_cpu_ptr(link_sta->pcpu_rx_stats);
-+              stats = this_cpu_ptr(rx->link_sta->pcpu_rx_stats);
-       else
--              stats = &link_sta->rx_stats;
-+              stats = &rx->link_sta->rx_stats;
-       stats->dropped++;
-       return true;
-@@ -4787,8 +4816,8 @@ static bool ieee80211_prepare_and_rx_han
-       struct ieee80211_local *local = rx->local;
-       struct ieee80211_sub_if_data *sdata = rx->sdata;
-       struct ieee80211_hdr *hdr = (void *)skb->data;
--      struct link_sta_info *link_sta = NULL;
--      struct ieee80211_link_data *link;
-+      struct link_sta_info *link_sta = rx->link_sta;
-+      struct ieee80211_link_data *link = rx->link;
-       rx->skb = skb;
-@@ -4810,35 +4839,6 @@ static bool ieee80211_prepare_and_rx_han
-       if (!ieee80211_accept_frame(rx))
-               return false;
--      if (rx->link_id >= 0) {
--              link = rcu_dereference(rx->sdata->link[rx->link_id]);
--
--              /* we might race link removal */
--              if (!link)
--                      return true;
--              rx->link = link;
--
--              if (rx->sta) {
--                      rx->link_sta =
--                              rcu_dereference(rx->sta->link[rx->link_id]);
--                      if (!rx->link_sta)
--                              return true;
--              }
--      } else {
--              if (rx->sta)
--                      rx->link_sta = &rx->sta->deflink;
--
--              rx->link = &sdata->deflink;
--      }
--
--      if (unlikely(!is_multicast_ether_addr(hdr->addr1) &&
--                   rx->link_id >= 0 && rx->sta && rx->sta->sta.mlo)) {
--              link_sta = rcu_dereference(rx->sta->link[rx->link_id]);
--
--              if (WARN_ON_ONCE(!link_sta))
--                      return true;
--      }
--
-       if (!consume) {
-               struct skb_shared_hwtstamps *shwt;
-@@ -4858,7 +4858,7 @@ static bool ieee80211_prepare_and_rx_han
-               shwt->hwtstamp = skb_hwtstamps(skb)->hwtstamp;
-       }
--      if (unlikely(link_sta)) {
-+      if (unlikely(rx->sta && rx->sta->sta.mlo)) {
-               /* translate to MLD addresses */
-               if (ether_addr_equal(link->conf->addr, hdr->addr1))
-                       ether_addr_copy(hdr->addr1, rx->sdata->vif.addr);
-@@ -4888,6 +4888,7 @@ static void __ieee80211_rx_handle_8023(s
-       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
-       struct ieee80211_fast_rx *fast_rx;
-       struct ieee80211_rx_data rx;
-+      int link_id = -1;
-       memset(&rx, 0, sizeof(rx));
-       rx.skb = skb;
-@@ -4904,12 +4905,8 @@ static void __ieee80211_rx_handle_8023(s
-       if (!pubsta)
-               goto drop;
--      rx.sta = container_of(pubsta, struct sta_info, sta);
--      rx.sdata = rx.sta->sdata;
--
--      if (status->link_valid &&
--          !ieee80211_rx_is_valid_sta_link_id(pubsta, status->link_id))
--              goto drop;
-+      if (status->link_valid)
-+              link_id = status->link_id;
-       /*
-        * TODO: Should the frame be dropped if the right link_id is not
-@@ -4918,19 +4915,8 @@ static void __ieee80211_rx_handle_8023(s
-        * link_id is used only for stats purpose and updating the stats on
-        * the deflink is fine?
-        */
--      if (status->link_valid)
--              rx.link_id = status->link_id;
--
--      if (rx.link_id >= 0) {
--              struct ieee80211_link_data *link;
--
--              link =  rcu_dereference(rx.sdata->link[rx.link_id]);
--              if (!link)
--                      goto drop;
--              rx.link = link;
--      } else {
--              rx.link = &rx.sdata->deflink;
--      }
-+      if (!ieee80211_rx_data_set_sta(&rx, pubsta, link_id))
-+              goto drop;
-       fast_rx = rcu_dereference(rx.sta->fast_rx);
-       if (!fast_rx)
-@@ -4948,6 +4934,8 @@ static bool ieee80211_rx_for_interface(s
- {
-       struct link_sta_info *link_sta;
-       struct ieee80211_hdr *hdr = (void *)skb->data;
-+      struct sta_info *sta;
-+      int link_id = -1;
-       /*
-        * Look up link station first, in case there's a
-@@ -4957,24 +4945,19 @@ static bool ieee80211_rx_for_interface(s
-        */
-       link_sta = link_sta_info_get_bss(rx->sdata, hdr->addr2);
-       if (link_sta) {
--              rx->sta = link_sta->sta;
--              rx->link_id = link_sta->link_id;
-+              sta = link_sta->sta;
-+              link_id = link_sta->link_id;
-       } else {
-               struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
--              rx->sta = sta_info_get_bss(rx->sdata, hdr->addr2);
--              if (rx->sta) {
--                      if (status->link_valid &&
--                          !ieee80211_rx_is_valid_sta_link_id(&rx->sta->sta,
--                                                             status->link_id))
--                              return false;
--
--                      rx->link_id = status->link_valid ? status->link_id : -1;
--              } else {
--                      rx->link_id = -1;
--              }
-+              sta = sta_info_get_bss(rx->sdata, hdr->addr2);
-+              if (status->link_valid)
-+                      link_id = status->link_id;
-       }
-+      if (!ieee80211_rx_data_set_sta(rx, &sta->sta, link_id))
-+              return false;
-+
-       return ieee80211_prepare_and_rx_handle(rx, skb, consume);
- }
-@@ -5033,19 +5016,15 @@ static void __ieee80211_rx_handle_packet
-       if (ieee80211_is_data(fc)) {
-               struct sta_info *sta, *prev_sta;
--              u8 link_id = status->link_id;
-+              int link_id = -1;
--              if (pubsta) {
--                      rx.sta = container_of(pubsta, struct sta_info, sta);
--                      rx.sdata = rx.sta->sdata;
-+              if (status->link_valid)
-+                      link_id = status->link_id;
--                      if (status->link_valid &&
--                          !ieee80211_rx_is_valid_sta_link_id(pubsta, link_id))
-+              if (pubsta) {
-+                      if (!ieee80211_rx_data_set_sta(&rx, pubsta, link_id))
-                               goto out;
--                      if (status->link_valid)
--                              rx.link_id = status->link_id;
--
-                       /*
-                        * In MLO connection, fetch the link_id using addr2
-                        * when the driver does not pass link_id in status.
-@@ -5063,7 +5042,7 @@ static void __ieee80211_rx_handle_packet
-                               if (!link_sta)
-                                       goto out;
--                              rx.link_id = link_sta->link_id;
-+                              ieee80211_rx_data_set_link(&rx, link_sta->link_id);
-                       }
-                       if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
-@@ -5079,30 +5058,27 @@ static void __ieee80211_rx_handle_packet
-                               continue;
-                       }
--                      if ((status->link_valid &&
--                           !ieee80211_rx_is_valid_sta_link_id(&prev_sta->sta,
--                                                              link_id)) ||
--                          (!status->link_valid && prev_sta->sta.mlo))
-+                      rx.sdata = prev_sta->sdata;
-+                      if (!ieee80211_rx_data_set_sta(&rx, &prev_sta->sta,
-+                                                     link_id))
-+                              goto out;
-+
-+                      if (!status->link_valid && prev_sta->sta.mlo)
-                               continue;
--                      rx.link_id = status->link_valid ? link_id : -1;
--                      rx.sta = prev_sta;
--                      rx.sdata = prev_sta->sdata;
-                       ieee80211_prepare_and_rx_handle(&rx, skb, false);
-                       prev_sta = sta;
-               }
-               if (prev_sta) {
--                      if ((status->link_valid &&
--                           !ieee80211_rx_is_valid_sta_link_id(&prev_sta->sta,
--                                                              link_id)) ||
--                          (!status->link_valid && prev_sta->sta.mlo))
-+                      rx.sdata = prev_sta->sdata;
-+                      if (!ieee80211_rx_data_set_sta(&rx, &prev_sta->sta,
-+                                                     link_id))
-                               goto out;
--                      rx.link_id = status->link_valid ? link_id : -1;
--                      rx.sta = prev_sta;
--                      rx.sdata = prev_sta->sdata;
-+                      if (!status->link_valid && prev_sta->sta.mlo)
-+                              goto out;
-                       if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
-                               return;
diff --git a/package/kernel/mac80211/patches/subsys/308-v6.2-wifi-mac80211-fix-MLO-AP_VLAN-check.patch b/package/kernel/mac80211/patches/subsys/308-v6.2-wifi-mac80211-fix-MLO-AP_VLAN-check.patch
new file mode 100644 (file)
index 0000000..2d181e3
--- /dev/null
@@ -0,0 +1,25 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 14 Dec 2022 13:46:38 +0100
+Subject: [PATCH] wifi: mac80211: fix MLO + AP_VLAN check
+
+Instead of preventing adding AP_VLAN to MLO enabled APs, this check was
+preventing adding more than one 4-addr AP_VLAN regardless of the MLO status.
+Fix this by adding missing extra checks.
+
+Fixes: ae960ee90bb1 ("wifi: mac80211: prevent VLANs on MLDs")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -364,7 +364,9 @@ static int ieee80211_check_concurrent_if
+                       /* No support for VLAN with MLO yet */
+                       if (iftype == NL80211_IFTYPE_AP_VLAN &&
+-                          nsdata->wdev.use_4addr)
++                          sdata->wdev.use_4addr &&
++                          nsdata->vif.type == NL80211_IFTYPE_AP &&
++                          nsdata->vif.valid_links)
+                               return -EOPNOTSUPP;
+                       /*
diff --git a/package/kernel/mac80211/patches/subsys/308-wifi-mac80211-fix-MLO-AP_VLAN-check.patch b/package/kernel/mac80211/patches/subsys/308-wifi-mac80211-fix-MLO-AP_VLAN-check.patch
deleted file mode 100644 (file)
index 2d181e3..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Wed, 14 Dec 2022 13:46:38 +0100
-Subject: [PATCH] wifi: mac80211: fix MLO + AP_VLAN check
-
-Instead of preventing adding AP_VLAN to MLO enabled APs, this check was
-preventing adding more than one 4-addr AP_VLAN regardless of the MLO status.
-Fix this by adding missing extra checks.
-
-Fixes: ae960ee90bb1 ("wifi: mac80211: prevent VLANs on MLDs")
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/iface.c
-+++ b/net/mac80211/iface.c
-@@ -364,7 +364,9 @@ static int ieee80211_check_concurrent_if
-                       /* No support for VLAN with MLO yet */
-                       if (iftype == NL80211_IFTYPE_AP_VLAN &&
--                          nsdata->wdev.use_4addr)
-+                          sdata->wdev.use_4addr &&
-+                          nsdata->vif.type == NL80211_IFTYPE_AP &&
-+                          nsdata->vif.valid_links)
-                               return -EOPNOTSUPP;
-                       /*
diff --git a/package/kernel/mac80211/patches/subsys/310-mac80211-add-support-for-restricting-netdev-features.patch b/package/kernel/mac80211/patches/subsys/310-mac80211-add-support-for-restricting-netdev-features.patch
deleted file mode 100644 (file)
index 3d286d0..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sun, 9 Oct 2022 20:15:46 +0200
-Subject: [PATCH] mac80211: add support for restricting netdev features per vif
-
-This can be used to selectively disable feature flags for checksum offload,
-scatter/gather or GSO by changing vif->netdev_features.
-Removing features from vif->netdev_features does not affect the netdev
-features themselves, but instead fixes up skbs in the tx path so that the
-offloads are not needed in the driver.
-
-Aside from making it easier to deal with vif type based hardware limitations,
-this also makes it possible to optimize performance on hardware without native
-GSO support by declaring GSO support in hw->netdev_features and removing it
-from vif->netdev_features. This allows mac80211 to handle GSO segmentation
-after the sta lookup, but before itxq enqueue, thus reducing the number of
-unnecessary sta lookups, as well as some other per-packet processing.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/include/net/fq_impl.h
-+++ b/include/net/fq_impl.h
-@@ -200,6 +200,7 @@ static void fq_tin_enqueue(struct fq *fq
-                          fq_skb_free_t free_func)
- {
-       struct fq_flow *flow;
-+      struct sk_buff *next;
-       bool oom;
-       lockdep_assert_held(&fq->lock);
-@@ -214,11 +215,15 @@ static void fq_tin_enqueue(struct fq *fq
-       }
-       flow->tin = tin;
--      flow->backlog += skb->len;
--      tin->backlog_bytes += skb->len;
--      tin->backlog_packets++;
--      fq->memory_usage += skb->truesize;
--      fq->backlog++;
-+      skb_list_walk_safe(skb, skb, next) {
-+              skb_mark_not_on_list(skb);
-+              flow->backlog += skb->len;
-+              tin->backlog_bytes += skb->len;
-+              tin->backlog_packets++;
-+              fq->memory_usage += skb->truesize;
-+              fq->backlog++;
-+              __skb_queue_tail(&flow->queue, skb);
-+      }
-       if (list_empty(&flow->flowchain)) {
-               flow->deficit = fq->quantum;
-@@ -226,7 +231,6 @@ static void fq_tin_enqueue(struct fq *fq
-                             &tin->new_flows);
-       }
--      __skb_queue_tail(&flow->queue, skb);
-       oom = (fq->memory_usage > fq->memory_limit);
-       while (fq->backlog > fq->limit || oom) {
-               flow = fq_find_fattest_flow(fq);
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -1807,6 +1807,10 @@ struct ieee80211_vif_cfg {
-  * @addr: address of this interface
-  * @p2p: indicates whether this AP or STA interface is a p2p
-  *    interface, i.e. a GO or p2p-sta respectively
-+ * @netdev_features: tx netdev features supported by the hardware for this
-+ *    vif. mac80211 initializes this to hw->netdev_features, and the driver
-+ *    can mask out specific tx features. mac80211 will handle software fixup
-+ *    for masked offloads (GSO, CSUM)
-  * @driver_flags: flags/capabilities the driver has for this interface,
-  *    these need to be set (or cleared) when the interface is added
-  *    or, if supported by the driver, the interface type is changed
-@@ -1848,6 +1852,7 @@ struct ieee80211_vif {
-       struct ieee80211_txq *txq;
-+      netdev_features_t netdev_features;
-       u32 driver_flags;
-       u32 offload_flags;
---- a/net/mac80211/iface.c
-+++ b/net/mac80211/iface.c
-@@ -2181,6 +2181,7 @@ int ieee80211_if_add(struct ieee80211_lo
-               ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
-               ndev->hw_features |= ndev->features &
-                                       MAC80211_SUPPORTED_FEATURES_TX;
-+              sdata->vif.netdev_features = local->hw.netdev_features;
-               netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops);
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -1355,7 +1355,11 @@ static struct txq_info *ieee80211_get_tx
- static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
- {
--      IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
-+      struct sk_buff *next;
-+      codel_time_t now = codel_get_time();
-+
-+      skb_list_walk_safe(skb, skb, next)
-+              IEEE80211_SKB_CB(skb)->control.enqueue_time = now;
- }
- static u32 codel_skb_len_func(const struct sk_buff *skb)
-@@ -3578,55 +3582,79 @@ ieee80211_xmit_fast_finish(struct ieee80
-       return TX_CONTINUE;
- }
--static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
--                              struct sta_info *sta,
--                              struct ieee80211_fast_tx *fast_tx,
--                              struct sk_buff *skb)
-+static netdev_features_t
-+ieee80211_sdata_netdev_features(struct ieee80211_sub_if_data *sdata)
- {
--      struct ieee80211_local *local = sdata->local;
--      u16 ethertype = (skb->data[12] << 8) | skb->data[13];
--      int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
--      int hw_headroom = sdata->local->hw.extra_tx_headroom;
--      struct ethhdr eth;
--      struct ieee80211_tx_info *info;
--      struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
--      struct ieee80211_tx_data tx;
--      ieee80211_tx_result r;
--      struct tid_ampdu_tx *tid_tx = NULL;
--      u8 tid = IEEE80211_NUM_TIDS;
-+      if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
-+              return sdata->vif.netdev_features;
--      /* control port protocol needs a lot of special handling */
--      if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
--              return false;
-+      if (!sdata->bss)
-+              return 0;
--      /* only RFC 1042 SNAP */
--      if (ethertype < ETH_P_802_3_MIN)
--              return false;
-+      sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
-+      return sdata->vif.netdev_features;
-+}
--      /* don't handle TX status request here either */
--      if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
--              return false;
-+static struct sk_buff *
-+ieee80211_tx_skb_fixup(struct sk_buff *skb, netdev_features_t features)
-+{
-+      if (skb_is_gso(skb)) {
-+              struct sk_buff *segs;
--      if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
--              tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
--              tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
--              if (tid_tx) {
--                      if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
--                              return false;
--                      if (tid_tx->timeout)
--                              tid_tx->last_tx = jiffies;
--              }
-+              segs = skb_gso_segment(skb, features);
-+              if (!segs)
-+                      return skb;
-+              if (IS_ERR(segs))
-+                      goto free;
-+
-+              consume_skb(skb);
-+              return segs;
-       }
--      /* after this point (skb is modified) we cannot return false */
-+      if (skb_needs_linearize(skb, features) && __skb_linearize(skb))
-+              goto free;
-+
-+      if (skb->ip_summed == CHECKSUM_PARTIAL) {
-+              int ofs = skb_checksum_start_offset(skb);
-+
-+              if (skb->encapsulation)
-+                      skb_set_inner_transport_header(skb, ofs);
-+              else
-+                      skb_set_transport_header(skb, ofs);
-+
-+              if (skb_csum_hwoffload_help(skb, features))
-+                      goto free;
-+      }
-+
-+      skb_mark_not_on_list(skb);
-+      return skb;
-+
-+free:
-+      kfree_skb(skb);
-+      return NULL;
-+}
-+
-+static void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
-+                                struct sta_info *sta,
-+                                struct ieee80211_fast_tx *fast_tx,
-+                                struct sk_buff *skb, u8 tid, bool ampdu)
-+{
-+      struct ieee80211_local *local = sdata->local;
-+      struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
-+      struct ieee80211_tx_info *info;
-+      struct ieee80211_tx_data tx;
-+      ieee80211_tx_result r;
-+      int hw_headroom = sdata->local->hw.extra_tx_headroom;
-+      int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
-+      struct ethhdr eth;
-       skb = skb_share_check(skb, GFP_ATOMIC);
-       if (unlikely(!skb))
--              return true;
-+              return;
-       if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
-           ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
--              return true;
-+              return;
-       /* will not be crypto-handled beyond what we do here, so use false
-        * as the may-encrypt argument for the resize to not account for
-@@ -3635,10 +3663,8 @@ static bool ieee80211_xmit_fast(struct i
-       if (unlikely(ieee80211_skb_resize(sdata, skb,
-                                         max_t(int, extra_head + hw_headroom -
-                                                    skb_headroom(skb), 0),
--                                        ENCRYPT_NO))) {
--              kfree_skb(skb);
--              return true;
--      }
-+                                        ENCRYPT_NO)))
-+              goto free;
-       memcpy(&eth, skb->data, ETH_HLEN - 2);
-       hdr = skb_push(skb, extra_head);
-@@ -3652,7 +3678,7 @@ static bool ieee80211_xmit_fast(struct i
-       info->control.vif = &sdata->vif;
-       info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT |
-                     IEEE80211_TX_CTL_DONTFRAG |
--                    (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
-+                    (ampdu ? IEEE80211_TX_CTL_AMPDU : 0);
-       info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT |
-                             u32_encode_bits(IEEE80211_LINK_UNSPECIFIED,
-                                             IEEE80211_TX_CTRL_MLO_LINK);
-@@ -3676,16 +3702,14 @@ static bool ieee80211_xmit_fast(struct i
-       tx.key = fast_tx->key;
-       if (ieee80211_queue_skb(local, sdata, sta, skb))
--              return true;
-+              return;
-       tx.skb = skb;
-       r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
-                                      fast_tx->key, &tx);
-       tx.skb = NULL;
--      if (r == TX_DROP) {
--              kfree_skb(skb);
--              return true;
--      }
-+      if (r == TX_DROP)
-+              goto free;
-       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               sdata = container_of(sdata->bss,
-@@ -3693,6 +3717,56 @@ static bool ieee80211_xmit_fast(struct i
-       __skb_queue_tail(&tx.skbs, skb);
-       ieee80211_tx_frags(local, &sdata->vif, sta, &tx.skbs, false);
-+      return;
-+
-+free:
-+      kfree_skb(skb);
-+}
-+
-+static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
-+                              struct sta_info *sta,
-+                              struct ieee80211_fast_tx *fast_tx,
-+                              struct sk_buff *skb)
-+{
-+      u16 ethertype = (skb->data[12] << 8) | skb->data[13];
-+      struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
-+      struct tid_ampdu_tx *tid_tx = NULL;
-+      struct sk_buff *next;
-+      u8 tid = IEEE80211_NUM_TIDS;
-+
-+      /* control port protocol needs a lot of special handling */
-+      if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
-+              return false;
-+
-+      /* only RFC 1042 SNAP */
-+      if (ethertype < ETH_P_802_3_MIN)
-+              return false;
-+
-+      /* don't handle TX status request here either */
-+      if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
-+              return false;
-+
-+      if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
-+              tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
-+              tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
-+              if (tid_tx) {
-+                      if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
-+                              return false;
-+                      if (tid_tx->timeout)
-+                              tid_tx->last_tx = jiffies;
-+              }
-+      }
-+
-+      /* after this point (skb is modified) we cannot return false */
-+      skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
-+      if (!skb)
-+              return true;
-+
-+      skb_list_walk_safe(skb, skb, next) {
-+              skb_mark_not_on_list(skb);
-+              __ieee80211_xmit_fast(sdata, sta, fast_tx, skb, tid, tid_tx);
-+      }
-+
-       return true;
- }
-@@ -4193,31 +4267,14 @@ void __ieee80211_subif_start_xmit(struct
-                       goto out;
-       }
--      if (skb_is_gso(skb)) {
--              struct sk_buff *segs;
--
--              segs = skb_gso_segment(skb, 0);
--              if (IS_ERR(segs)) {
--                      goto out_free;
--              } else if (segs) {
--                      consume_skb(skb);
--                      skb = segs;
--              }
--      } else {
--              /* we cannot process non-linear frames on this path */
--              if (skb_linearize(skb))
--                      goto out_free;
--
--              /* the frame could be fragmented, software-encrypted, and other
--               * things so we cannot really handle checksum offload with it -
--               * fix it up in software before we handle anything else.
--               */
--              if (skb->ip_summed == CHECKSUM_PARTIAL) {
--                      skb_set_transport_header(skb,
--                                               skb_checksum_start_offset(skb));
--                      if (skb_checksum_help(skb))
--                              goto out_free;
--              }
-+      /* the frame could be fragmented, software-encrypted, and other
-+       * things so we cannot really handle checksum or GSO offload.
-+       * fix it up in software before we handle anything else.
-+       */
-+      skb = ieee80211_tx_skb_fixup(skb, 0);
-+      if (!skb) {
-+              len = 0;
-+              goto out;
-       }
-       skb_list_walk_safe(skb, skb, next) {
-@@ -4435,9 +4492,11 @@ normal:
-       return NETDEV_TX_OK;
- }
--static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
--                            struct sk_buff *skb, struct sta_info *sta,
--                            bool txpending)
-+
-+
-+static bool __ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
-+                              struct sk_buff *skb, struct sta_info *sta,
-+                              bool txpending)
- {
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_tx_control control = {};
-@@ -4446,14 +4505,6 @@ static bool ieee80211_tx_8023(struct iee
-       unsigned long flags;
-       int q = info->hw_queue;
--      if (sta)
--              sk_pacing_shift_update(skb->sk, local->hw.tx_sk_pacing_shift);
--
--      ieee80211_tpt_led_trig_tx(local, skb->len);
--
--      if (ieee80211_queue_skb(local, sdata, sta, skb))
--              return true;
--
-       spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-       if (local->queue_stop_reasons[q] ||
-@@ -4480,6 +4531,26 @@ static bool ieee80211_tx_8023(struct iee
-       return true;
- }
-+static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
-+                            struct sk_buff *skb, struct sta_info *sta,
-+                            bool txpending)
-+{
-+      struct ieee80211_local *local = sdata->local;
-+      struct sk_buff *next;
-+      bool ret = true;
-+
-+      if (ieee80211_queue_skb(local, sdata, sta, skb))
-+              return true;
-+
-+      skb_list_walk_safe(skb, skb, next) {
-+              skb_mark_not_on_list(skb);
-+              if (!__ieee80211_tx_8023(sdata, skb, sta, txpending))
-+                      ret = false;
-+      }
-+
-+      return ret;
-+}
-+
- static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
-                               struct net_device *dev, struct sta_info *sta,
-                               struct ieee80211_key *key, struct sk_buff *skb)
-@@ -4487,9 +4558,13 @@ static void ieee80211_8023_xmit(struct i
-       struct ieee80211_tx_info *info;
-       struct ieee80211_local *local = sdata->local;
-       struct tid_ampdu_tx *tid_tx;
-+      struct sk_buff *seg, *next;
-+      unsigned int skbs = 0, len = 0;
-+      u16 queue;
-       u8 tid;
--      skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb));
-+      queue = ieee80211_select_queue(sdata, sta, skb);
-+      skb_set_queue_mapping(skb, queue);
-       if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
-           test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
-@@ -4499,9 +4574,6 @@ static void ieee80211_8023_xmit(struct i
-       if (unlikely(!skb))
-               return;
--      info = IEEE80211_SKB_CB(skb);
--      memset(info, 0, sizeof(*info));
--
-       ieee80211_aggr_check(sdata, sta, skb);
-       tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
-@@ -4515,22 +4587,20 @@ static void ieee80211_8023_xmit(struct i
-                       return;
-               }
--              info->flags |= IEEE80211_TX_CTL_AMPDU;
-               if (tid_tx->timeout)
-                       tid_tx->last_tx = jiffies;
-       }
--      if (unlikely(skb->sk &&
--                   skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
--              info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
--                                                           &info->flags, NULL);
-+      skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
-+      if (!skb)
-+              return;
--      info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
-+      info = IEEE80211_SKB_CB(skb);
-+      memset(info, 0, sizeof(*info));
-+      if (tid_tx)
-+              info->flags |= IEEE80211_TX_CTL_AMPDU;
--      dev_sw_netstats_tx_add(dev, 1, skb->len);
--
--      sta->deflink.tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
--      sta->deflink.tx_stats.packets[skb_get_queue_mapping(skb)]++;
-+      info->hw_queue = sdata->vif.hw_queue[queue];
-       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-               sdata = container_of(sdata->bss,
-@@ -4542,6 +4612,24 @@ static void ieee80211_8023_xmit(struct i
-       if (key)
-               info->control.hw_key = &key->conf;
-+      skb_list_walk_safe(skb, seg, next) {
-+              skbs++;
-+              len += seg->len;
-+              if (seg != skb)
-+                      memcpy(IEEE80211_SKB_CB(seg), info, sizeof(*info));
-+      }
-+
-+      if (unlikely(skb->sk &&
-+                   skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
-+              info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
-+                                                           &info->flags, NULL);
-+
-+      dev_sw_netstats_tx_add(dev, skbs, len);
-+      sta->deflink.tx_stats.packets[queue] += skbs;
-+      sta->deflink.tx_stats.bytes[queue] += len;
-+
-+      ieee80211_tpt_led_trig_tx(local, len);
-+
-       ieee80211_tx_8023(sdata, skb, sta, false);
-       return;
-@@ -4583,6 +4671,7 @@ netdev_tx_t ieee80211_subif_start_xmit_8
-                   key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))
-               goto skip_offload;
-+      sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
-       ieee80211_8023_xmit(sdata, dev, sta, key, skb);
-       goto out;
diff --git a/package/kernel/mac80211/patches/subsys/310-v6.2-mac80211-add-support-for-restricting-netdev-features.patch b/package/kernel/mac80211/patches/subsys/310-v6.2-mac80211-add-support-for-restricting-netdev-features.patch
new file mode 100644 (file)
index 0000000..3d286d0
--- /dev/null
@@ -0,0 +1,506 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sun, 9 Oct 2022 20:15:46 +0200
+Subject: [PATCH] mac80211: add support for restricting netdev features per vif
+
+This can be used to selectively disable feature flags for checksum offload,
+scatter/gather or GSO by changing vif->netdev_features.
+Removing features from vif->netdev_features does not affect the netdev
+features themselves, but instead fixes up skbs in the tx path so that the
+offloads are not needed in the driver.
+
+Aside from making it easier to deal with vif type based hardware limitations,
+this also makes it possible to optimize performance on hardware without native
+GSO support by declaring GSO support in hw->netdev_features and removing it
+from vif->netdev_features. This allows mac80211 to handle GSO segmentation
+after the sta lookup, but before itxq enqueue, thus reducing the number of
+unnecessary sta lookups, as well as some other per-packet processing.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/net/fq_impl.h
++++ b/include/net/fq_impl.h
+@@ -200,6 +200,7 @@ static void fq_tin_enqueue(struct fq *fq
+                          fq_skb_free_t free_func)
+ {
+       struct fq_flow *flow;
++      struct sk_buff *next;
+       bool oom;
+       lockdep_assert_held(&fq->lock);
+@@ -214,11 +215,15 @@ static void fq_tin_enqueue(struct fq *fq
+       }
+       flow->tin = tin;
+-      flow->backlog += skb->len;
+-      tin->backlog_bytes += skb->len;
+-      tin->backlog_packets++;
+-      fq->memory_usage += skb->truesize;
+-      fq->backlog++;
++      skb_list_walk_safe(skb, skb, next) {
++              skb_mark_not_on_list(skb);
++              flow->backlog += skb->len;
++              tin->backlog_bytes += skb->len;
++              tin->backlog_packets++;
++              fq->memory_usage += skb->truesize;
++              fq->backlog++;
++              __skb_queue_tail(&flow->queue, skb);
++      }
+       if (list_empty(&flow->flowchain)) {
+               flow->deficit = fq->quantum;
+@@ -226,7 +231,6 @@ static void fq_tin_enqueue(struct fq *fq
+                             &tin->new_flows);
+       }
+-      __skb_queue_tail(&flow->queue, skb);
+       oom = (fq->memory_usage > fq->memory_limit);
+       while (fq->backlog > fq->limit || oom) {
+               flow = fq_find_fattest_flow(fq);
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -1807,6 +1807,10 @@ struct ieee80211_vif_cfg {
+  * @addr: address of this interface
+  * @p2p: indicates whether this AP or STA interface is a p2p
+  *    interface, i.e. a GO or p2p-sta respectively
++ * @netdev_features: tx netdev features supported by the hardware for this
++ *    vif. mac80211 initializes this to hw->netdev_features, and the driver
++ *    can mask out specific tx features. mac80211 will handle software fixup
++ *    for masked offloads (GSO, CSUM)
+  * @driver_flags: flags/capabilities the driver has for this interface,
+  *    these need to be set (or cleared) when the interface is added
+  *    or, if supported by the driver, the interface type is changed
+@@ -1848,6 +1852,7 @@ struct ieee80211_vif {
+       struct ieee80211_txq *txq;
++      netdev_features_t netdev_features;
+       u32 driver_flags;
+       u32 offload_flags;
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -2181,6 +2181,7 @@ int ieee80211_if_add(struct ieee80211_lo
+               ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+               ndev->hw_features |= ndev->features &
+                                       MAC80211_SUPPORTED_FEATURES_TX;
++              sdata->vif.netdev_features = local->hw.netdev_features;
+               netdev_set_default_ethtool_ops(ndev, &ieee80211_ethtool_ops);
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -1355,7 +1355,11 @@ static struct txq_info *ieee80211_get_tx
+ static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb)
+ {
+-      IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time();
++      struct sk_buff *next;
++      codel_time_t now = codel_get_time();
++
++      skb_list_walk_safe(skb, skb, next)
++              IEEE80211_SKB_CB(skb)->control.enqueue_time = now;
+ }
+ static u32 codel_skb_len_func(const struct sk_buff *skb)
+@@ -3578,55 +3582,79 @@ ieee80211_xmit_fast_finish(struct ieee80
+       return TX_CONTINUE;
+ }
+-static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
+-                              struct sta_info *sta,
+-                              struct ieee80211_fast_tx *fast_tx,
+-                              struct sk_buff *skb)
++static netdev_features_t
++ieee80211_sdata_netdev_features(struct ieee80211_sub_if_data *sdata)
+ {
+-      struct ieee80211_local *local = sdata->local;
+-      u16 ethertype = (skb->data[12] << 8) | skb->data[13];
+-      int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
+-      int hw_headroom = sdata->local->hw.extra_tx_headroom;
+-      struct ethhdr eth;
+-      struct ieee80211_tx_info *info;
+-      struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
+-      struct ieee80211_tx_data tx;
+-      ieee80211_tx_result r;
+-      struct tid_ampdu_tx *tid_tx = NULL;
+-      u8 tid = IEEE80211_NUM_TIDS;
++      if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN)
++              return sdata->vif.netdev_features;
+-      /* control port protocol needs a lot of special handling */
+-      if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
+-              return false;
++      if (!sdata->bss)
++              return 0;
+-      /* only RFC 1042 SNAP */
+-      if (ethertype < ETH_P_802_3_MIN)
+-              return false;
++      sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
++      return sdata->vif.netdev_features;
++}
+-      /* don't handle TX status request here either */
+-      if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
+-              return false;
++static struct sk_buff *
++ieee80211_tx_skb_fixup(struct sk_buff *skb, netdev_features_t features)
++{
++      if (skb_is_gso(skb)) {
++              struct sk_buff *segs;
+-      if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
+-              tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+-              tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
+-              if (tid_tx) {
+-                      if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
+-                              return false;
+-                      if (tid_tx->timeout)
+-                              tid_tx->last_tx = jiffies;
+-              }
++              segs = skb_gso_segment(skb, features);
++              if (!segs)
++                      return skb;
++              if (IS_ERR(segs))
++                      goto free;
++
++              consume_skb(skb);
++              return segs;
+       }
+-      /* after this point (skb is modified) we cannot return false */
++      if (skb_needs_linearize(skb, features) && __skb_linearize(skb))
++              goto free;
++
++      if (skb->ip_summed == CHECKSUM_PARTIAL) {
++              int ofs = skb_checksum_start_offset(skb);
++
++              if (skb->encapsulation)
++                      skb_set_inner_transport_header(skb, ofs);
++              else
++                      skb_set_transport_header(skb, ofs);
++
++              if (skb_csum_hwoffload_help(skb, features))
++                      goto free;
++      }
++
++      skb_mark_not_on_list(skb);
++      return skb;
++
++free:
++      kfree_skb(skb);
++      return NULL;
++}
++
++static void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
++                                struct sta_info *sta,
++                                struct ieee80211_fast_tx *fast_tx,
++                                struct sk_buff *skb, u8 tid, bool ampdu)
++{
++      struct ieee80211_local *local = sdata->local;
++      struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
++      struct ieee80211_tx_info *info;
++      struct ieee80211_tx_data tx;
++      ieee80211_tx_result r;
++      int hw_headroom = sdata->local->hw.extra_tx_headroom;
++      int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
++      struct ethhdr eth;
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (unlikely(!skb))
+-              return true;
++              return;
+       if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
+           ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
+-              return true;
++              return;
+       /* will not be crypto-handled beyond what we do here, so use false
+        * as the may-encrypt argument for the resize to not account for
+@@ -3635,10 +3663,8 @@ static bool ieee80211_xmit_fast(struct i
+       if (unlikely(ieee80211_skb_resize(sdata, skb,
+                                         max_t(int, extra_head + hw_headroom -
+                                                    skb_headroom(skb), 0),
+-                                        ENCRYPT_NO))) {
+-              kfree_skb(skb);
+-              return true;
+-      }
++                                        ENCRYPT_NO)))
++              goto free;
+       memcpy(&eth, skb->data, ETH_HLEN - 2);
+       hdr = skb_push(skb, extra_head);
+@@ -3652,7 +3678,7 @@ static bool ieee80211_xmit_fast(struct i
+       info->control.vif = &sdata->vif;
+       info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT |
+                     IEEE80211_TX_CTL_DONTFRAG |
+-                    (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
++                    (ampdu ? IEEE80211_TX_CTL_AMPDU : 0);
+       info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT |
+                             u32_encode_bits(IEEE80211_LINK_UNSPECIFIED,
+                                             IEEE80211_TX_CTRL_MLO_LINK);
+@@ -3676,16 +3702,14 @@ static bool ieee80211_xmit_fast(struct i
+       tx.key = fast_tx->key;
+       if (ieee80211_queue_skb(local, sdata, sta, skb))
+-              return true;
++              return;
+       tx.skb = skb;
+       r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
+                                      fast_tx->key, &tx);
+       tx.skb = NULL;
+-      if (r == TX_DROP) {
+-              kfree_skb(skb);
+-              return true;
+-      }
++      if (r == TX_DROP)
++              goto free;
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               sdata = container_of(sdata->bss,
+@@ -3693,6 +3717,56 @@ static bool ieee80211_xmit_fast(struct i
+       __skb_queue_tail(&tx.skbs, skb);
+       ieee80211_tx_frags(local, &sdata->vif, sta, &tx.skbs, false);
++      return;
++
++free:
++      kfree_skb(skb);
++}
++
++static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
++                              struct sta_info *sta,
++                              struct ieee80211_fast_tx *fast_tx,
++                              struct sk_buff *skb)
++{
++      u16 ethertype = (skb->data[12] << 8) | skb->data[13];
++      struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
++      struct tid_ampdu_tx *tid_tx = NULL;
++      struct sk_buff *next;
++      u8 tid = IEEE80211_NUM_TIDS;
++
++      /* control port protocol needs a lot of special handling */
++      if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
++              return false;
++
++      /* only RFC 1042 SNAP */
++      if (ethertype < ETH_P_802_3_MIN)
++              return false;
++
++      /* don't handle TX status request here either */
++      if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
++              return false;
++
++      if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
++              tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
++              tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
++              if (tid_tx) {
++                      if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
++                              return false;
++                      if (tid_tx->timeout)
++                              tid_tx->last_tx = jiffies;
++              }
++      }
++
++      /* after this point (skb is modified) we cannot return false */
++      skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
++      if (!skb)
++              return true;
++
++      skb_list_walk_safe(skb, skb, next) {
++              skb_mark_not_on_list(skb);
++              __ieee80211_xmit_fast(sdata, sta, fast_tx, skb, tid, tid_tx);
++      }
++
+       return true;
+ }
+@@ -4193,31 +4267,14 @@ void __ieee80211_subif_start_xmit(struct
+                       goto out;
+       }
+-      if (skb_is_gso(skb)) {
+-              struct sk_buff *segs;
+-
+-              segs = skb_gso_segment(skb, 0);
+-              if (IS_ERR(segs)) {
+-                      goto out_free;
+-              } else if (segs) {
+-                      consume_skb(skb);
+-                      skb = segs;
+-              }
+-      } else {
+-              /* we cannot process non-linear frames on this path */
+-              if (skb_linearize(skb))
+-                      goto out_free;
+-
+-              /* the frame could be fragmented, software-encrypted, and other
+-               * things so we cannot really handle checksum offload with it -
+-               * fix it up in software before we handle anything else.
+-               */
+-              if (skb->ip_summed == CHECKSUM_PARTIAL) {
+-                      skb_set_transport_header(skb,
+-                                               skb_checksum_start_offset(skb));
+-                      if (skb_checksum_help(skb))
+-                              goto out_free;
+-              }
++      /* the frame could be fragmented, software-encrypted, and other
++       * things so we cannot really handle checksum or GSO offload.
++       * fix it up in software before we handle anything else.
++       */
++      skb = ieee80211_tx_skb_fixup(skb, 0);
++      if (!skb) {
++              len = 0;
++              goto out;
+       }
+       skb_list_walk_safe(skb, skb, next) {
+@@ -4435,9 +4492,11 @@ normal:
+       return NETDEV_TX_OK;
+ }
+-static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
+-                            struct sk_buff *skb, struct sta_info *sta,
+-                            bool txpending)
++
++
++static bool __ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
++                              struct sk_buff *skb, struct sta_info *sta,
++                              bool txpending)
+ {
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_tx_control control = {};
+@@ -4446,14 +4505,6 @@ static bool ieee80211_tx_8023(struct iee
+       unsigned long flags;
+       int q = info->hw_queue;
+-      if (sta)
+-              sk_pacing_shift_update(skb->sk, local->hw.tx_sk_pacing_shift);
+-
+-      ieee80211_tpt_led_trig_tx(local, skb->len);
+-
+-      if (ieee80211_queue_skb(local, sdata, sta, skb))
+-              return true;
+-
+       spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+       if (local->queue_stop_reasons[q] ||
+@@ -4480,6 +4531,26 @@ static bool ieee80211_tx_8023(struct iee
+       return true;
+ }
++static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
++                            struct sk_buff *skb, struct sta_info *sta,
++                            bool txpending)
++{
++      struct ieee80211_local *local = sdata->local;
++      struct sk_buff *next;
++      bool ret = true;
++
++      if (ieee80211_queue_skb(local, sdata, sta, skb))
++              return true;
++
++      skb_list_walk_safe(skb, skb, next) {
++              skb_mark_not_on_list(skb);
++              if (!__ieee80211_tx_8023(sdata, skb, sta, txpending))
++                      ret = false;
++      }
++
++      return ret;
++}
++
+ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
+                               struct net_device *dev, struct sta_info *sta,
+                               struct ieee80211_key *key, struct sk_buff *skb)
+@@ -4487,9 +4558,13 @@ static void ieee80211_8023_xmit(struct i
+       struct ieee80211_tx_info *info;
+       struct ieee80211_local *local = sdata->local;
+       struct tid_ampdu_tx *tid_tx;
++      struct sk_buff *seg, *next;
++      unsigned int skbs = 0, len = 0;
++      u16 queue;
+       u8 tid;
+-      skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb));
++      queue = ieee80211_select_queue(sdata, sta, skb);
++      skb_set_queue_mapping(skb, queue);
+       if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
+           test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
+@@ -4499,9 +4574,6 @@ static void ieee80211_8023_xmit(struct i
+       if (unlikely(!skb))
+               return;
+-      info = IEEE80211_SKB_CB(skb);
+-      memset(info, 0, sizeof(*info));
+-
+       ieee80211_aggr_check(sdata, sta, skb);
+       tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+@@ -4515,22 +4587,20 @@ static void ieee80211_8023_xmit(struct i
+                       return;
+               }
+-              info->flags |= IEEE80211_TX_CTL_AMPDU;
+               if (tid_tx->timeout)
+                       tid_tx->last_tx = jiffies;
+       }
+-      if (unlikely(skb->sk &&
+-                   skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
+-              info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
+-                                                           &info->flags, NULL);
++      skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
++      if (!skb)
++              return;
+-      info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
++      info = IEEE80211_SKB_CB(skb);
++      memset(info, 0, sizeof(*info));
++      if (tid_tx)
++              info->flags |= IEEE80211_TX_CTL_AMPDU;
+-      dev_sw_netstats_tx_add(dev, 1, skb->len);
+-
+-      sta->deflink.tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
+-      sta->deflink.tx_stats.packets[skb_get_queue_mapping(skb)]++;
++      info->hw_queue = sdata->vif.hw_queue[queue];
+       if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+               sdata = container_of(sdata->bss,
+@@ -4542,6 +4612,24 @@ static void ieee80211_8023_xmit(struct i
+       if (key)
+               info->control.hw_key = &key->conf;
++      skb_list_walk_safe(skb, seg, next) {
++              skbs++;
++              len += seg->len;
++              if (seg != skb)
++                      memcpy(IEEE80211_SKB_CB(seg), info, sizeof(*info));
++      }
++
++      if (unlikely(skb->sk &&
++                   skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
++              info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
++                                                           &info->flags, NULL);
++
++      dev_sw_netstats_tx_add(dev, skbs, len);
++      sta->deflink.tx_stats.packets[queue] += skbs;
++      sta->deflink.tx_stats.bytes[queue] += len;
++
++      ieee80211_tpt_led_trig_tx(local, len);
++
+       ieee80211_tx_8023(sdata, skb, sta, false);
+       return;
+@@ -4583,6 +4671,7 @@ netdev_tx_t ieee80211_subif_start_xmit_8
+                   key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))
+               goto skip_offload;
++      sk_pacing_shift_update(skb->sk, sdata->local->hw.tx_sk_pacing_shift);
+       ieee80211_8023_xmit(sdata, dev, sta, key, skb);
+       goto out;
diff --git a/package/kernel/mac80211/patches/subsys/311-v6.2-wifi-mac80211-fix-and-simplify-unencrypted-drop-chec.patch b/package/kernel/mac80211/patches/subsys/311-v6.2-wifi-mac80211-fix-and-simplify-unencrypted-drop-chec.patch
new file mode 100644 (file)
index 0000000..804b02e
--- /dev/null
@@ -0,0 +1,87 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 1 Dec 2022 14:57:30 +0100
+Subject: [PATCH] wifi: mac80211: fix and simplify unencrypted drop check for
+ mesh
+
+ieee80211_drop_unencrypted is called from ieee80211_rx_h_mesh_fwding and
+ieee80211_frame_allowed.
+
+Since ieee80211_rx_h_mesh_fwding can forward packets for other mesh nodes
+and is called earlier, it needs to check the decryptions status and if the
+packet is using the control protocol on its own, instead of deferring to
+the later call from ieee80211_frame_allowed.
+
+Because of that, ieee80211_drop_unencrypted has a mesh specific check
+that skips over the mesh header in order to check the payload protocol.
+This code is invalid when called from ieee80211_frame_allowed, since that
+happens after the 802.11->802.3 conversion.
+
+Fix this by moving the mesh specific check directly into
+ieee80211_rx_h_mesh_fwding.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Link: https://lore.kernel.org/r/20221201135730.19723-1-nbd@nbd.name
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2403,7 +2403,6 @@ static int ieee80211_802_1x_port_control
+ static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
+ {
+-      struct ieee80211_hdr *hdr = (void *)rx->skb->data;
+       struct sk_buff *skb = rx->skb;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+@@ -2414,31 +2413,6 @@ static int ieee80211_drop_unencrypted(st
+       if (status->flag & RX_FLAG_DECRYPTED)
+               return 0;
+-      /* check mesh EAPOL frames first */
+-      if (unlikely(rx->sta && ieee80211_vif_is_mesh(&rx->sdata->vif) &&
+-                   ieee80211_is_data(fc))) {
+-              struct ieee80211s_hdr *mesh_hdr;
+-              u16 hdr_len = ieee80211_hdrlen(fc);
+-              u16 ethertype_offset;
+-              __be16 ethertype;
+-
+-              if (!ether_addr_equal(hdr->addr1, rx->sdata->vif.addr))
+-                      goto drop_check;
+-
+-              /* make sure fixed part of mesh header is there, also checks skb len */
+-              if (!pskb_may_pull(rx->skb, hdr_len + 6))
+-                      goto drop_check;
+-
+-              mesh_hdr = (struct ieee80211s_hdr *)(skb->data + hdr_len);
+-              ethertype_offset = hdr_len + ieee80211_get_mesh_hdrlen(mesh_hdr) +
+-                                 sizeof(rfc1042_header);
+-
+-              if (skb_copy_bits(rx->skb, ethertype_offset, &ethertype, 2) == 0 &&
+-                  ethertype == rx->sdata->control_port_protocol)
+-                      return 0;
+-      }
+-
+-drop_check:
+       /* Drop unencrypted frames if key is set. */
+       if (unlikely(!ieee80211_has_protected(fc) &&
+                    !ieee80211_is_any_nullfunc(fc) &&
+@@ -2892,8 +2866,16 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
+       hdr = (struct ieee80211_hdr *) skb->data;
+       mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+-      if (ieee80211_drop_unencrypted(rx, hdr->frame_control))
+-              return RX_DROP_MONITOR;
++      if (ieee80211_drop_unencrypted(rx, hdr->frame_control)) {
++              int offset = hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr) +
++                           sizeof(rfc1042_header);
++              __be16 ethertype;
++
++              if (!ether_addr_equal(hdr->addr1, rx->sdata->vif.addr) ||
++                  skb_copy_bits(rx->skb, offset, &ethertype, 2) != 0 ||
++                  ethertype != rx->sdata->control_port_protocol)
++                      return RX_DROP_MONITOR;
++      }
+       /* frame is in RMC, don't forward */
+       if (ieee80211_is_data(hdr->frame_control) &&
diff --git a/package/kernel/mac80211/patches/subsys/311-wifi-mac80211-fix-and-simplify-unencrypted-drop-chec.patch b/package/kernel/mac80211/patches/subsys/311-wifi-mac80211-fix-and-simplify-unencrypted-drop-chec.patch
deleted file mode 100644 (file)
index 804b02e..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 1 Dec 2022 14:57:30 +0100
-Subject: [PATCH] wifi: mac80211: fix and simplify unencrypted drop check for
- mesh
-
-ieee80211_drop_unencrypted is called from ieee80211_rx_h_mesh_fwding and
-ieee80211_frame_allowed.
-
-Since ieee80211_rx_h_mesh_fwding can forward packets for other mesh nodes
-and is called earlier, it needs to check the decryptions status and if the
-packet is using the control protocol on its own, instead of deferring to
-the later call from ieee80211_frame_allowed.
-
-Because of that, ieee80211_drop_unencrypted has a mesh specific check
-that skips over the mesh header in order to check the payload protocol.
-This code is invalid when called from ieee80211_frame_allowed, since that
-happens after the 802.11->802.3 conversion.
-
-Fix this by moving the mesh specific check directly into
-ieee80211_rx_h_mesh_fwding.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
-Link: https://lore.kernel.org/r/20221201135730.19723-1-nbd@nbd.name
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2403,7 +2403,6 @@ static int ieee80211_802_1x_port_control
- static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
- {
--      struct ieee80211_hdr *hdr = (void *)rx->skb->data;
-       struct sk_buff *skb = rx->skb;
-       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
-@@ -2414,31 +2413,6 @@ static int ieee80211_drop_unencrypted(st
-       if (status->flag & RX_FLAG_DECRYPTED)
-               return 0;
--      /* check mesh EAPOL frames first */
--      if (unlikely(rx->sta && ieee80211_vif_is_mesh(&rx->sdata->vif) &&
--                   ieee80211_is_data(fc))) {
--              struct ieee80211s_hdr *mesh_hdr;
--              u16 hdr_len = ieee80211_hdrlen(fc);
--              u16 ethertype_offset;
--              __be16 ethertype;
--
--              if (!ether_addr_equal(hdr->addr1, rx->sdata->vif.addr))
--                      goto drop_check;
--
--              /* make sure fixed part of mesh header is there, also checks skb len */
--              if (!pskb_may_pull(rx->skb, hdr_len + 6))
--                      goto drop_check;
--
--              mesh_hdr = (struct ieee80211s_hdr *)(skb->data + hdr_len);
--              ethertype_offset = hdr_len + ieee80211_get_mesh_hdrlen(mesh_hdr) +
--                                 sizeof(rfc1042_header);
--
--              if (skb_copy_bits(rx->skb, ethertype_offset, &ethertype, 2) == 0 &&
--                  ethertype == rx->sdata->control_port_protocol)
--                      return 0;
--      }
--
--drop_check:
-       /* Drop unencrypted frames if key is set. */
-       if (unlikely(!ieee80211_has_protected(fc) &&
-                    !ieee80211_is_any_nullfunc(fc) &&
-@@ -2892,8 +2866,16 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
-       hdr = (struct ieee80211_hdr *) skb->data;
-       mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
--      if (ieee80211_drop_unencrypted(rx, hdr->frame_control))
--              return RX_DROP_MONITOR;
-+      if (ieee80211_drop_unencrypted(rx, hdr->frame_control)) {
-+              int offset = hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr) +
-+                           sizeof(rfc1042_header);
-+              __be16 ethertype;
-+
-+              if (!ether_addr_equal(hdr->addr1, rx->sdata->vif.addr) ||
-+                  skb_copy_bits(rx->skb, offset, &ethertype, 2) != 0 ||
-+                  ethertype != rx->sdata->control_port_protocol)
-+                      return RX_DROP_MONITOR;
-+      }
-       /* frame is in RMC, don't forward */
-       if (ieee80211_is_data(hdr->frame_control) &&
diff --git a/package/kernel/mac80211/patches/subsys/312-v6.3-wifi-cfg80211-move-A-MSDU-check-in-ieee80211_data_to.patch b/package/kernel/mac80211/patches/subsys/312-v6.3-wifi-cfg80211-move-A-MSDU-check-in-ieee80211_data_to.patch
new file mode 100644 (file)
index 0000000..f668905
--- /dev/null
@@ -0,0 +1,25 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 2 Dec 2022 13:53:11 +0100
+Subject: [PATCH] wifi: cfg80211: move A-MSDU check in
+ ieee80211_data_to_8023_exthdr
+
+When parsing the outer A-MSDU header, don't check for inner bridge tunnel
+or RFC1042 headers. This is handled by ieee80211_amsdu_to_8023s already.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/wireless/util.c
++++ b/net/wireless/util.c
+@@ -631,8 +631,9 @@ int ieee80211_data_to_8023_exthdr(struct
+               break;
+       }
+-      if (likely(skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
+-                 ((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) &&
++      if (likely(!is_amsdu &&
++                 skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
++                 ((ether_addr_equal(payload.hdr, rfc1042_header) &&
+                    payload.proto != htons(ETH_P_AARP) &&
+                    payload.proto != htons(ETH_P_IPX)) ||
+                   ether_addr_equal(payload.hdr, bridge_tunnel_header)))) {
diff --git a/package/kernel/mac80211/patches/subsys/312-wifi-cfg80211-move-A-MSDU-check-in-ieee80211_data_to.patch b/package/kernel/mac80211/patches/subsys/312-wifi-cfg80211-move-A-MSDU-check-in-ieee80211_data_to.patch
deleted file mode 100644 (file)
index f668905..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 2 Dec 2022 13:53:11 +0100
-Subject: [PATCH] wifi: cfg80211: move A-MSDU check in
- ieee80211_data_to_8023_exthdr
-
-When parsing the outer A-MSDU header, don't check for inner bridge tunnel
-or RFC1042 headers. This is handled by ieee80211_amsdu_to_8023s already.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -631,8 +631,9 @@ int ieee80211_data_to_8023_exthdr(struct
-               break;
-       }
--      if (likely(skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
--                 ((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) &&
-+      if (likely(!is_amsdu &&
-+                 skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
-+                 ((ether_addr_equal(payload.hdr, rfc1042_header) &&
-                    payload.proto != htons(ETH_P_AARP) &&
-                    payload.proto != htons(ETH_P_IPX)) ||
-                   ether_addr_equal(payload.hdr, bridge_tunnel_header)))) {
diff --git a/package/kernel/mac80211/patches/subsys/313-v6.3-wifi-cfg80211-factor-out-bridge-tunnel-RFC1042-heade.patch b/package/kernel/mac80211/patches/subsys/313-v6.3-wifi-cfg80211-factor-out-bridge-tunnel-RFC1042-heade.patch
new file mode 100644 (file)
index 0000000..8641057
--- /dev/null
@@ -0,0 +1,76 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 2 Dec 2022 13:54:15 +0100
+Subject: [PATCH] wifi: cfg80211: factor out bridge tunnel / RFC1042 header
+ check
+
+The same check is done in multiple places, unify it.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/wireless/util.c
++++ b/net/wireless/util.c
+@@ -542,6 +542,21 @@ unsigned int ieee80211_get_mesh_hdrlen(s
+ }
+ EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
++static bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto)
++{
++      const __be16 *hdr_proto = hdr + ETH_ALEN;
++
++      if (!(ether_addr_equal(hdr, rfc1042_header) &&
++            *hdr_proto != htons(ETH_P_AARP) &&
++            *hdr_proto != htons(ETH_P_IPX)) &&
++          !ether_addr_equal(hdr, bridge_tunnel_header))
++              return false;
++
++      *proto = *hdr_proto;
++
++      return true;
++}
++
+ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
+                                 const u8 *addr, enum nl80211_iftype iftype,
+                                 u8 data_offset, bool is_amsdu)
+@@ -633,14 +648,9 @@ int ieee80211_data_to_8023_exthdr(struct
+       if (likely(!is_amsdu &&
+                  skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
+-                 ((ether_addr_equal(payload.hdr, rfc1042_header) &&
+-                   payload.proto != htons(ETH_P_AARP) &&
+-                   payload.proto != htons(ETH_P_IPX)) ||
+-                  ether_addr_equal(payload.hdr, bridge_tunnel_header)))) {
+-              /* remove RFC1042 or Bridge-Tunnel encapsulation and
+-               * replace EtherType */
++                 ieee80211_get_8023_tunnel_proto(&payload, &tmp.h_proto))) {
++              /* remove RFC1042 or Bridge-Tunnel encapsulation */
+               hdrlen += ETH_ALEN + 2;
+-              tmp.h_proto = payload.proto;
+               skb_postpull_rcsum(skb, &payload, ETH_ALEN + 2);
+       } else {
+               tmp.h_proto = htons(skb->len - hdrlen);
+@@ -756,8 +766,6 @@ void ieee80211_amsdu_to_8023s(struct sk_
+ {
+       unsigned int hlen = ALIGN(extra_headroom, 4);
+       struct sk_buff *frame = NULL;
+-      u16 ethertype;
+-      u8 *payload;
+       int offset = 0, remaining;
+       struct ethhdr eth;
+       bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
+@@ -811,14 +819,8 @@ void ieee80211_amsdu_to_8023s(struct sk_
+               frame->dev = skb->dev;
+               frame->priority = skb->priority;
+-              payload = frame->data;
+-              ethertype = (payload[6] << 8) | payload[7];
+-              if (likely((ether_addr_equal(payload, rfc1042_header) &&
+-                          ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+-                         ether_addr_equal(payload, bridge_tunnel_header))) {
+-                      eth.h_proto = htons(ethertype);
++              if (likely(ieee80211_get_8023_tunnel_proto(frame->data, &eth.h_proto)))
+                       skb_pull(frame, ETH_ALEN + 2);
+-              }
+               memcpy(skb_push(frame, sizeof(eth)), &eth, sizeof(eth));
+               __skb_queue_tail(list, frame);
diff --git a/package/kernel/mac80211/patches/subsys/313-wifi-cfg80211-factor-out-bridge-tunnel-RFC1042-heade.patch b/package/kernel/mac80211/patches/subsys/313-wifi-cfg80211-factor-out-bridge-tunnel-RFC1042-heade.patch
deleted file mode 100644 (file)
index 8641057..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 2 Dec 2022 13:54:15 +0100
-Subject: [PATCH] wifi: cfg80211: factor out bridge tunnel / RFC1042 header
- check
-
-The same check is done in multiple places, unify it.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -542,6 +542,21 @@ unsigned int ieee80211_get_mesh_hdrlen(s
- }
- EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
-+static bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto)
-+{
-+      const __be16 *hdr_proto = hdr + ETH_ALEN;
-+
-+      if (!(ether_addr_equal(hdr, rfc1042_header) &&
-+            *hdr_proto != htons(ETH_P_AARP) &&
-+            *hdr_proto != htons(ETH_P_IPX)) &&
-+          !ether_addr_equal(hdr, bridge_tunnel_header))
-+              return false;
-+
-+      *proto = *hdr_proto;
-+
-+      return true;
-+}
-+
- int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
-                                 const u8 *addr, enum nl80211_iftype iftype,
-                                 u8 data_offset, bool is_amsdu)
-@@ -633,14 +648,9 @@ int ieee80211_data_to_8023_exthdr(struct
-       if (likely(!is_amsdu &&
-                  skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
--                 ((ether_addr_equal(payload.hdr, rfc1042_header) &&
--                   payload.proto != htons(ETH_P_AARP) &&
--                   payload.proto != htons(ETH_P_IPX)) ||
--                  ether_addr_equal(payload.hdr, bridge_tunnel_header)))) {
--              /* remove RFC1042 or Bridge-Tunnel encapsulation and
--               * replace EtherType */
-+                 ieee80211_get_8023_tunnel_proto(&payload, &tmp.h_proto))) {
-+              /* remove RFC1042 or Bridge-Tunnel encapsulation */
-               hdrlen += ETH_ALEN + 2;
--              tmp.h_proto = payload.proto;
-               skb_postpull_rcsum(skb, &payload, ETH_ALEN + 2);
-       } else {
-               tmp.h_proto = htons(skb->len - hdrlen);
-@@ -756,8 +766,6 @@ void ieee80211_amsdu_to_8023s(struct sk_
- {
-       unsigned int hlen = ALIGN(extra_headroom, 4);
-       struct sk_buff *frame = NULL;
--      u16 ethertype;
--      u8 *payload;
-       int offset = 0, remaining;
-       struct ethhdr eth;
-       bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
-@@ -811,14 +819,8 @@ void ieee80211_amsdu_to_8023s(struct sk_
-               frame->dev = skb->dev;
-               frame->priority = skb->priority;
--              payload = frame->data;
--              ethertype = (payload[6] << 8) | payload[7];
--              if (likely((ether_addr_equal(payload, rfc1042_header) &&
--                          ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
--                         ether_addr_equal(payload, bridge_tunnel_header))) {
--                      eth.h_proto = htons(ethertype);
-+              if (likely(ieee80211_get_8023_tunnel_proto(frame->data, &eth.h_proto)))
-                       skb_pull(frame, ETH_ALEN + 2);
--              }
-               memcpy(skb_push(frame, sizeof(eth)), &eth, sizeof(eth));
-               __skb_queue_tail(list, frame);
diff --git a/package/kernel/mac80211/patches/subsys/314-v6.3-wifi-mac80211-remove-mesh-forwarding-congestion-chec.patch b/package/kernel/mac80211/patches/subsys/314-v6.3-wifi-mac80211-remove-mesh-forwarding-congestion-chec.patch
new file mode 100644 (file)
index 0000000..515176f
--- /dev/null
@@ -0,0 +1,54 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 2 Dec 2022 17:01:46 +0100
+Subject: [PATCH] wifi: mac80211: remove mesh forwarding congestion check
+
+Now that all drivers use iTXQ, it does not make sense to check to drop
+tx forwarding packets when the driver has stopped the queues.
+fq_codel will take care of dropping packets when the queues fill up
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/debugfs_netdev.c
++++ b/net/mac80211/debugfs_netdev.c
+@@ -603,8 +603,6 @@ IEEE80211_IF_FILE(fwded_mcast, u.mesh.ms
+ IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
+ IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
+ IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
+-IEEE80211_IF_FILE(dropped_frames_congestion,
+-                u.mesh.mshstats.dropped_frames_congestion, DEC);
+ IEEE80211_IF_FILE(dropped_frames_no_route,
+                 u.mesh.mshstats.dropped_frames_no_route, DEC);
+@@ -740,7 +738,6 @@ static void add_mesh_stats(struct ieee80
+       MESHSTATS_ADD(fwded_frames);
+       MESHSTATS_ADD(dropped_frames_ttl);
+       MESHSTATS_ADD(dropped_frames_no_route);
+-      MESHSTATS_ADD(dropped_frames_congestion);
+ #undef MESHSTATS_ADD
+ }
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -329,7 +329,6 @@ struct mesh_stats {
+       __u32 fwded_frames;             /* Mesh total forwarded frames */
+       __u32 dropped_frames_ttl;       /* Not transmitted since mesh_ttl == 0*/
+       __u32 dropped_frames_no_route;  /* Not transmitted, no route found */
+-      __u32 dropped_frames_congestion;/* Not forwarded due to congestion */
+ };
+ #define PREQ_Q_F_START                0x1
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2926,11 +2926,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
+               return RX_CONTINUE;
+       ac = ieee802_1d_to_ac[skb->priority];
+-      q = sdata->vif.hw_queue[ac];
+-      if (ieee80211_queue_stopped(&local->hw, q)) {
+-              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
+-              return RX_DROP_MONITOR;
+-      }
+       skb_set_queue_mapping(skb, ac);
+       if (!--mesh_hdr->ttl) {
diff --git a/package/kernel/mac80211/patches/subsys/314-wifi-mac80211-remove-mesh-forwarding-congestion-chec.patch b/package/kernel/mac80211/patches/subsys/314-wifi-mac80211-remove-mesh-forwarding-congestion-chec.patch
deleted file mode 100644 (file)
index 515176f..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 2 Dec 2022 17:01:46 +0100
-Subject: [PATCH] wifi: mac80211: remove mesh forwarding congestion check
-
-Now that all drivers use iTXQ, it does not make sense to check to drop
-tx forwarding packets when the driver has stopped the queues.
-fq_codel will take care of dropping packets when the queues fill up
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/debugfs_netdev.c
-+++ b/net/mac80211/debugfs_netdev.c
-@@ -603,8 +603,6 @@ IEEE80211_IF_FILE(fwded_mcast, u.mesh.ms
- IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC);
- IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC);
- IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC);
--IEEE80211_IF_FILE(dropped_frames_congestion,
--                u.mesh.mshstats.dropped_frames_congestion, DEC);
- IEEE80211_IF_FILE(dropped_frames_no_route,
-                 u.mesh.mshstats.dropped_frames_no_route, DEC);
-@@ -740,7 +738,6 @@ static void add_mesh_stats(struct ieee80
-       MESHSTATS_ADD(fwded_frames);
-       MESHSTATS_ADD(dropped_frames_ttl);
-       MESHSTATS_ADD(dropped_frames_no_route);
--      MESHSTATS_ADD(dropped_frames_congestion);
- #undef MESHSTATS_ADD
- }
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -329,7 +329,6 @@ struct mesh_stats {
-       __u32 fwded_frames;             /* Mesh total forwarded frames */
-       __u32 dropped_frames_ttl;       /* Not transmitted since mesh_ttl == 0*/
-       __u32 dropped_frames_no_route;  /* Not transmitted, no route found */
--      __u32 dropped_frames_congestion;/* Not forwarded due to congestion */
- };
- #define PREQ_Q_F_START                0x1
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2926,11 +2926,6 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
-               return RX_CONTINUE;
-       ac = ieee802_1d_to_ac[skb->priority];
--      q = sdata->vif.hw_queue[ac];
--      if (ieee80211_queue_stopped(&local->hw, q)) {
--              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
--              return RX_DROP_MONITOR;
--      }
-       skb_set_queue_mapping(skb, ac);
-       if (!--mesh_hdr->ttl) {
diff --git a/package/kernel/mac80211/patches/subsys/315-v6.3-wifi-mac80211-fix-receiving-A-MSDU-frames-on-mesh-in.patch b/package/kernel/mac80211/patches/subsys/315-v6.3-wifi-mac80211-fix-receiving-A-MSDU-frames-on-mesh-in.patch
new file mode 100644 (file)
index 0000000..6aec9bc
--- /dev/null
@@ -0,0 +1,753 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 6 Dec 2022 11:15:02 +0100
+Subject: [PATCH] wifi: mac80211: fix receiving A-MSDU frames on mesh
+ interfaces
+
+The current mac80211 mesh A-MSDU receive path fails to parse A-MSDU packets
+on mesh interfaces, because it assumes that the Mesh Control field is always
+directly after the 802.11 header.
+802.11-2020 9.3.2.2.2 Figure 9-70 shows that the Mesh Control field is
+actually part of the A-MSDU subframe header.
+This makes more sense, since it allows packets for multiple different
+destinations to be included in the same A-MSDU, as long as RA and TID are
+still the same.
+Another issue is the fact that the A-MSDU subframe length field was apparently
+accidentally defined as little-endian in the standard.
+
+In order to fix this, the mesh forwarding path needs happen at a different
+point in the receive path.
+
+ieee80211_data_to_8023_exthdr is changed to ignore the mesh control field
+and leave it in after the ethernet header. This also affects the source/dest
+MAC address fields, which now in the case of mesh point to the mesh SA/DA.
+
+ieee80211_amsdu_to_8023s is changed to deal with the endian difference and
+to add the Mesh Control length to the subframe length, since it's not covered
+by the MSDU length field.
+
+With these changes, the mac80211 will get the same packet structure for
+converted regular data packets and unpacked A-MSDU subframes.
+
+The mesh forwarding checks are now only performed after the A-MSDU decap.
+For locally received packets, the Mesh Control header is stripped away.
+For forwarded packets, a new 802.11 header gets added.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
++++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
+@@ -33,7 +33,7 @@ static int mwifiex_11n_dispatch_amsdu_pk
+               skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
+               ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
+-                                       priv->wdev.iftype, 0, NULL, NULL);
++                                       priv->wdev.iftype, 0, NULL, NULL, false);
+               while (!skb_queue_empty(&list)) {
+                       struct rx_packet_hdr *rx_hdr;
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -6208,11 +6208,36 @@ static inline int ieee80211_data_to_8023
+  * @extra_headroom: The hardware extra headroom for SKBs in the @list.
+  * @check_da: DA to check in the inner ethernet header, or NULL
+  * @check_sa: SA to check in the inner ethernet header, or NULL
++ * @mesh_control: A-MSDU subframe header includes the mesh control field
+  */
+ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
+                             const u8 *addr, enum nl80211_iftype iftype,
+                             const unsigned int extra_headroom,
+-                            const u8 *check_da, const u8 *check_sa);
++                            const u8 *check_da, const u8 *check_sa,
++                            bool mesh_control);
++
++/**
++ * ieee80211_get_8023_tunnel_proto - get RFC1042 or bridge tunnel encap protocol
++ *
++ * Check for RFC1042 or bridge tunnel header and fetch the encapsulated
++ * protocol.
++ *
++ * @hdr: pointer to the MSDU payload
++ * @proto: destination pointer to store the protocol
++ * Return: true if encapsulation was found
++ */
++bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto);
++
++/**
++ * ieee80211_strip_8023_mesh_hdr - strip mesh header from converted 802.3 frames
++ *
++ * Strip the mesh header, which was left in by ieee80211_data_to_8023 as part
++ * of the MSDU data. Also move any source/destination addresses from the mesh
++ * header to the ethernet header (if present).
++ *
++ * @skb: The 802.3 frame with embedded mesh header
++ */
++int ieee80211_strip_8023_mesh_hdr(struct sk_buff *skb);
+ /**
+  * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2720,6 +2720,174 @@ ieee80211_deliver_skb(struct ieee80211_r
+       }
+ }
++static ieee80211_rx_result
++ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta,
++                     struct sk_buff *skb)
++{
++#ifdef CPTCFG_MAC80211_MESH
++      struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
++      struct ieee80211_local *local = sdata->local;
++      uint16_t fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA;
++      struct ieee80211_hdr hdr = {
++              .frame_control = cpu_to_le16(fc)
++      };
++      struct ieee80211_hdr *fwd_hdr;
++      struct ieee80211s_hdr *mesh_hdr;
++      struct ieee80211_tx_info *info;
++      struct sk_buff *fwd_skb;
++      struct ethhdr *eth;
++      bool multicast;
++      int tailroom = 0;
++      int hdrlen, mesh_hdrlen;
++      u8 *qos;
++
++      if (!ieee80211_vif_is_mesh(&sdata->vif))
++              return RX_CONTINUE;
++
++      if (!pskb_may_pull(skb, sizeof(*eth) + 6))
++              return RX_DROP_MONITOR;
++
++      mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(*eth));
++      mesh_hdrlen = ieee80211_get_mesh_hdrlen(mesh_hdr);
++
++      if (!pskb_may_pull(skb, sizeof(*eth) + mesh_hdrlen))
++              return RX_DROP_MONITOR;
++
++      eth = (struct ethhdr *)skb->data;
++      multicast = is_multicast_ether_addr(eth->h_dest);
++
++      mesh_hdr = (struct ieee80211s_hdr *)(eth + 1);
++      if (!mesh_hdr->ttl)
++              return RX_DROP_MONITOR;
++
++      /* frame is in RMC, don't forward */
++      if (is_multicast_ether_addr(eth->h_dest) &&
++          mesh_rmc_check(sdata, eth->h_source, mesh_hdr))
++              return RX_DROP_MONITOR;
++
++      /* Frame has reached destination.  Don't forward */
++      if (ether_addr_equal(sdata->vif.addr, eth->h_dest))
++              goto rx_accept;
++
++      if (!ifmsh->mshcfg.dot11MeshForwarding) {
++              if (is_multicast_ether_addr(eth->h_dest))
++                      goto rx_accept;
++
++              return RX_DROP_MONITOR;
++      }
++
++      /* forward packet */
++      if (sdata->crypto_tx_tailroom_needed_cnt)
++              tailroom = IEEE80211_ENCRYPT_TAILROOM;
++
++      if (!--mesh_hdr->ttl) {
++              if (multicast)
++                      goto rx_accept;
++
++              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
++              return RX_DROP_MONITOR;
++      }
++
++      if (mesh_hdr->flags & MESH_FLAGS_AE) {
++              struct mesh_path *mppath;
++              char *proxied_addr;
++
++              if (multicast)
++                      proxied_addr = mesh_hdr->eaddr1;
++              else if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
++                      /* has_a4 already checked in ieee80211_rx_mesh_check */
++                      proxied_addr = mesh_hdr->eaddr2;
++              else
++                      return RX_DROP_MONITOR;
++
++              rcu_read_lock();
++              mppath = mpp_path_lookup(sdata, proxied_addr);
++              if (!mppath) {
++                      mpp_path_add(sdata, proxied_addr, eth->h_source);
++              } else {
++                      spin_lock_bh(&mppath->state_lock);
++                      if (!ether_addr_equal(mppath->mpp, eth->h_source))
++                              memcpy(mppath->mpp, eth->h_source, ETH_ALEN);
++                      mppath->exp_time = jiffies;
++                      spin_unlock_bh(&mppath->state_lock);
++              }
++              rcu_read_unlock();
++      }
++
++      skb_set_queue_mapping(skb, ieee802_1d_to_ac[skb->priority]);
++
++      ieee80211_fill_mesh_addresses(&hdr, &hdr.frame_control,
++                                    eth->h_dest, eth->h_source);
++      hdrlen = ieee80211_hdrlen(hdr.frame_control);
++      if (multicast) {
++              int extra_head = sizeof(struct ieee80211_hdr) - sizeof(*eth);
++
++              fwd_skb = skb_copy_expand(skb, local->tx_headroom + extra_head +
++                                             IEEE80211_ENCRYPT_HEADROOM,
++                                        tailroom, GFP_ATOMIC);
++              if (!fwd_skb)
++                      goto rx_accept;
++      } else {
++              fwd_skb = skb;
++              skb = NULL;
++
++              if (skb_cow_head(fwd_skb, hdrlen - sizeof(struct ethhdr)))
++                      return RX_DROP_UNUSABLE;
++      }
++
++      fwd_hdr = skb_push(fwd_skb, hdrlen - sizeof(struct ethhdr));
++      memcpy(fwd_hdr, &hdr, hdrlen - 2);
++      qos = ieee80211_get_qos_ctl(fwd_hdr);
++      qos[0] = qos[1] = 0;
++
++      skb_reset_mac_header(fwd_skb);
++      hdrlen += mesh_hdrlen;
++      if (ieee80211_get_8023_tunnel_proto(fwd_skb->data + hdrlen,
++                                          &fwd_skb->protocol))
++              hdrlen += ETH_ALEN;
++      else
++              fwd_skb->protocol = htons(fwd_skb->len - hdrlen);
++      skb_set_network_header(fwd_skb, hdrlen);
++
++      info = IEEE80211_SKB_CB(fwd_skb);
++      memset(info, 0, sizeof(*info));
++      info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
++      info->control.vif = &sdata->vif;
++      info->control.jiffies = jiffies;
++      if (multicast) {
++              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
++              memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
++              /* update power mode indication when forwarding */
++              ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
++      } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
++              /* mesh power mode flags updated in mesh_nexthop_lookup */
++              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
++      } else {
++              /* unable to resolve next hop */
++              if (sta)
++                      mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
++                                         hdr.addr3, 0,
++                                         WLAN_REASON_MESH_PATH_NOFORWARD,
++                                         sta->sta.addr);
++              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
++              kfree_skb(fwd_skb);
++              goto rx_accept;
++      }
++
++      IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
++      fwd_skb->dev = sdata->dev;
++      ieee80211_add_pending_skb(local, fwd_skb);
++
++rx_accept:
++      if (!skb)
++              return RX_QUEUED;
++
++      ieee80211_strip_8023_mesh_hdr(skb);
++#endif
++
++      return RX_CONTINUE;
++}
++
+ static ieee80211_rx_result debug_noinline
+ __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
+ {
+@@ -2728,8 +2896,10 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       __le16 fc = hdr->frame_control;
+       struct sk_buff_head frame_list;
++      static ieee80211_rx_result res;
+       struct ethhdr ethhdr;
+       const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
++      bool mesh = false;
+       if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
+               check_da = NULL;
+@@ -2746,6 +2916,8 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
+                       break;
+               case NL80211_IFTYPE_MESH_POINT:
+                       check_sa = NULL;
++                      check_da = NULL;
++                      mesh = true;
+                       break;
+               default:
+                       break;
+@@ -2763,17 +2935,29 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
+       ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
+                                rx->sdata->vif.type,
+                                rx->local->hw.extra_tx_headroom,
+-                               check_da, check_sa);
++                               check_da, check_sa, mesh);
+       while (!skb_queue_empty(&frame_list)) {
+               rx->skb = __skb_dequeue(&frame_list);
+-              if (!ieee80211_frame_allowed(rx, fc)) {
+-                      dev_kfree_skb(rx->skb);
++              res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
++              switch (res) {
++              case RX_QUEUED:
+                       continue;
++              case RX_CONTINUE:
++                      break;
++              default:
++                      goto free;
+               }
++              if (!ieee80211_frame_allowed(rx, fc))
++                      goto free;
++
+               ieee80211_deliver_skb(rx);
++              continue;
++
++free:
++              dev_kfree_skb(rx->skb);
+       }
+       return RX_QUEUED;
+@@ -2806,6 +2990,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx
+                       if (!rx->sdata->u.mgd.use_4addr)
+                               return RX_DROP_UNUSABLE;
+                       break;
++              case NL80211_IFTYPE_MESH_POINT:
++                      break;
+               default:
+                       return RX_DROP_UNUSABLE;
+               }
+@@ -2834,155 +3020,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx
+       return __ieee80211_rx_h_amsdu(rx, 0);
+ }
+-#ifdef CPTCFG_MAC80211_MESH
+-static ieee80211_rx_result
+-ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
+-{
+-      struct ieee80211_hdr *fwd_hdr, *hdr;
+-      struct ieee80211_tx_info *info;
+-      struct ieee80211s_hdr *mesh_hdr;
+-      struct sk_buff *skb = rx->skb, *fwd_skb;
+-      struct ieee80211_local *local = rx->local;
+-      struct ieee80211_sub_if_data *sdata = rx->sdata;
+-      struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+-      u16 ac, q, hdrlen;
+-      int tailroom = 0;
+-
+-      hdr = (struct ieee80211_hdr *) skb->data;
+-      hdrlen = ieee80211_hdrlen(hdr->frame_control);
+-
+-      /* make sure fixed part of mesh header is there, also checks skb len */
+-      if (!pskb_may_pull(rx->skb, hdrlen + 6))
+-              return RX_DROP_MONITOR;
+-
+-      mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+-
+-      /* make sure full mesh header is there, also checks skb len */
+-      if (!pskb_may_pull(rx->skb,
+-                         hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr)))
+-              return RX_DROP_MONITOR;
+-
+-      /* reload pointers */
+-      hdr = (struct ieee80211_hdr *) skb->data;
+-      mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
+-
+-      if (ieee80211_drop_unencrypted(rx, hdr->frame_control)) {
+-              int offset = hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr) +
+-                           sizeof(rfc1042_header);
+-              __be16 ethertype;
+-
+-              if (!ether_addr_equal(hdr->addr1, rx->sdata->vif.addr) ||
+-                  skb_copy_bits(rx->skb, offset, &ethertype, 2) != 0 ||
+-                  ethertype != rx->sdata->control_port_protocol)
+-                      return RX_DROP_MONITOR;
+-      }
+-
+-      /* frame is in RMC, don't forward */
+-      if (ieee80211_is_data(hdr->frame_control) &&
+-          is_multicast_ether_addr(hdr->addr1) &&
+-          mesh_rmc_check(rx->sdata, hdr->addr3, mesh_hdr))
+-              return RX_DROP_MONITOR;
+-
+-      if (!ieee80211_is_data(hdr->frame_control))
+-              return RX_CONTINUE;
+-
+-      if (!mesh_hdr->ttl)
+-              return RX_DROP_MONITOR;
+-
+-      if (mesh_hdr->flags & MESH_FLAGS_AE) {
+-              struct mesh_path *mppath;
+-              char *proxied_addr;
+-              char *mpp_addr;
+-
+-              if (is_multicast_ether_addr(hdr->addr1)) {
+-                      mpp_addr = hdr->addr3;
+-                      proxied_addr = mesh_hdr->eaddr1;
+-              } else if ((mesh_hdr->flags & MESH_FLAGS_AE) ==
+-                          MESH_FLAGS_AE_A5_A6) {
+-                      /* has_a4 already checked in ieee80211_rx_mesh_check */
+-                      mpp_addr = hdr->addr4;
+-                      proxied_addr = mesh_hdr->eaddr2;
+-              } else {
+-                      return RX_DROP_MONITOR;
+-              }
+-
+-              rcu_read_lock();
+-              mppath = mpp_path_lookup(sdata, proxied_addr);
+-              if (!mppath) {
+-                      mpp_path_add(sdata, proxied_addr, mpp_addr);
+-              } else {
+-                      spin_lock_bh(&mppath->state_lock);
+-                      if (!ether_addr_equal(mppath->mpp, mpp_addr))
+-                              memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
+-                      mppath->exp_time = jiffies;
+-                      spin_unlock_bh(&mppath->state_lock);
+-              }
+-              rcu_read_unlock();
+-      }
+-
+-      /* Frame has reached destination.  Don't forward */
+-      if (!is_multicast_ether_addr(hdr->addr1) &&
+-          ether_addr_equal(sdata->vif.addr, hdr->addr3))
+-              return RX_CONTINUE;
+-
+-      ac = ieee802_1d_to_ac[skb->priority];
+-      skb_set_queue_mapping(skb, ac);
+-
+-      if (!--mesh_hdr->ttl) {
+-              if (!is_multicast_ether_addr(hdr->addr1))
+-                      IEEE80211_IFSTA_MESH_CTR_INC(ifmsh,
+-                                                   dropped_frames_ttl);
+-              goto out;
+-      }
+-
+-      if (!ifmsh->mshcfg.dot11MeshForwarding)
+-              goto out;
+-
+-      if (sdata->crypto_tx_tailroom_needed_cnt)
+-              tailroom = IEEE80211_ENCRYPT_TAILROOM;
+-
+-      fwd_skb = skb_copy_expand(skb, local->tx_headroom +
+-                                     IEEE80211_ENCRYPT_HEADROOM,
+-                                tailroom, GFP_ATOMIC);
+-      if (!fwd_skb)
+-              goto out;
+-
+-      fwd_skb->dev = sdata->dev;
+-      fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
+-      fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY);
+-      info = IEEE80211_SKB_CB(fwd_skb);
+-      memset(info, 0, sizeof(*info));
+-      info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
+-      info->control.vif = &rx->sdata->vif;
+-      info->control.jiffies = jiffies;
+-      if (is_multicast_ether_addr(fwd_hdr->addr1)) {
+-              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
+-              memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
+-              /* update power mode indication when forwarding */
+-              ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
+-      } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
+-              /* mesh power mode flags updated in mesh_nexthop_lookup */
+-              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
+-      } else {
+-              /* unable to resolve next hop */
+-              mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
+-                                 fwd_hdr->addr3, 0,
+-                                 WLAN_REASON_MESH_PATH_NOFORWARD,
+-                                 fwd_hdr->addr2);
+-              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
+-              kfree_skb(fwd_skb);
+-              return RX_DROP_MONITOR;
+-      }
+-
+-      IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
+-      ieee80211_add_pending_skb(local, fwd_skb);
+- out:
+-      if (is_multicast_ether_addr(hdr->addr1))
+-              return RX_CONTINUE;
+-      return RX_DROP_MONITOR;
+-}
+-#endif
+-
+ static ieee80211_rx_result debug_noinline
+ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
+ {
+@@ -2991,6 +3028,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_
+       struct net_device *dev = sdata->dev;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
+       __le16 fc = hdr->frame_control;
++      static ieee80211_rx_result res;
+       bool port_control;
+       int err;
+@@ -3017,6 +3055,10 @@ ieee80211_rx_h_data(struct ieee80211_rx_
+       if (unlikely(err))
+               return RX_DROP_UNUSABLE;
++      res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
++      if (res != RX_CONTINUE)
++              return res;
++
+       if (!ieee80211_frame_allowed(rx, fc))
+               return RX_DROP_MONITOR;
+@@ -3987,10 +4029,6 @@ static void ieee80211_rx_handlers(struct
+               CALL_RXH(ieee80211_rx_h_defragment);
+               CALL_RXH(ieee80211_rx_h_michael_mic_verify);
+               /* must be after MMIC verify so header is counted in MPDU mic */
+-#ifdef CPTCFG_MAC80211_MESH
+-              if (ieee80211_vif_is_mesh(&rx->sdata->vif))
+-                      CALL_RXH(ieee80211_rx_h_mesh_fwding);
+-#endif
+               CALL_RXH(ieee80211_rx_h_amsdu);
+               CALL_RXH(ieee80211_rx_h_data);
+--- a/net/wireless/util.c
++++ b/net/wireless/util.c
+@@ -542,7 +542,7 @@ unsigned int ieee80211_get_mesh_hdrlen(s
+ }
+ EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
+-static bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto)
++bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto)
+ {
+       const __be16 *hdr_proto = hdr + ETH_ALEN;
+@@ -556,6 +556,49 @@ static bool ieee80211_get_8023_tunnel_pr
+       return true;
+ }
++EXPORT_SYMBOL(ieee80211_get_8023_tunnel_proto);
++
++int ieee80211_strip_8023_mesh_hdr(struct sk_buff *skb)
++{
++      const void *mesh_addr;
++      struct {
++              struct ethhdr eth;
++              u8 flags;
++      } payload;
++      int hdrlen;
++      int ret;
++
++      ret = skb_copy_bits(skb, 0, &payload, sizeof(payload));
++      if (ret)
++              return ret;
++
++      hdrlen = sizeof(payload.eth) + __ieee80211_get_mesh_hdrlen(payload.flags);
++
++      if (likely(pskb_may_pull(skb, hdrlen + 8) &&
++                 ieee80211_get_8023_tunnel_proto(skb->data + hdrlen,
++                                                 &payload.eth.h_proto)))
++              hdrlen += ETH_ALEN + 2;
++      else if (!pskb_may_pull(skb, hdrlen))
++              return -EINVAL;
++
++      mesh_addr = skb->data + sizeof(payload.eth) + ETH_ALEN;
++      switch (payload.flags & MESH_FLAGS_AE) {
++      case MESH_FLAGS_AE_A4:
++              memcpy(&payload.eth.h_source, mesh_addr, ETH_ALEN);
++              break;
++      case MESH_FLAGS_AE_A5_A6:
++              memcpy(&payload.eth.h_dest, mesh_addr, 2 * ETH_ALEN);
++              break;
++      default:
++              break;
++      }
++
++      pskb_pull(skb, hdrlen - sizeof(payload.eth));
++      memcpy(skb->data, &payload.eth, sizeof(payload.eth));
++
++      return 0;
++}
++EXPORT_SYMBOL(ieee80211_strip_8023_mesh_hdr);
+ int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
+                                 const u8 *addr, enum nl80211_iftype iftype,
+@@ -568,7 +611,6 @@ int ieee80211_data_to_8023_exthdr(struct
+       } payload;
+       struct ethhdr tmp;
+       u16 hdrlen;
+-      u8 mesh_flags = 0;
+       if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
+               return -1;
+@@ -589,12 +631,6 @@ int ieee80211_data_to_8023_exthdr(struct
+       memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
+       memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
+-      if (iftype == NL80211_IFTYPE_MESH_POINT &&
+-          skb_copy_bits(skb, hdrlen, &mesh_flags, 1) < 0)
+-              return -1;
+-
+-      mesh_flags &= MESH_FLAGS_AE;
+-
+       switch (hdr->frame_control &
+               cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
+       case cpu_to_le16(IEEE80211_FCTL_TODS):
+@@ -608,17 +644,6 @@ int ieee80211_data_to_8023_exthdr(struct
+                            iftype != NL80211_IFTYPE_AP_VLAN &&
+                            iftype != NL80211_IFTYPE_STATION))
+                       return -1;
+-              if (iftype == NL80211_IFTYPE_MESH_POINT) {
+-                      if (mesh_flags == MESH_FLAGS_AE_A4)
+-                              return -1;
+-                      if (mesh_flags == MESH_FLAGS_AE_A5_A6 &&
+-                          skb_copy_bits(skb, hdrlen +
+-                                        offsetof(struct ieee80211s_hdr, eaddr1),
+-                                        tmp.h_dest, 2 * ETH_ALEN) < 0)
+-                              return -1;
+-
+-                      hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
+-              }
+               break;
+       case cpu_to_le16(IEEE80211_FCTL_FROMDS):
+               if ((iftype != NL80211_IFTYPE_STATION &&
+@@ -627,16 +652,6 @@ int ieee80211_data_to_8023_exthdr(struct
+                   (is_multicast_ether_addr(tmp.h_dest) &&
+                    ether_addr_equal(tmp.h_source, addr)))
+                       return -1;
+-              if (iftype == NL80211_IFTYPE_MESH_POINT) {
+-                      if (mesh_flags == MESH_FLAGS_AE_A5_A6)
+-                              return -1;
+-                      if (mesh_flags == MESH_FLAGS_AE_A4 &&
+-                          skb_copy_bits(skb, hdrlen +
+-                                        offsetof(struct ieee80211s_hdr, eaddr1),
+-                                        tmp.h_source, ETH_ALEN) < 0)
+-                              return -1;
+-                      hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
+-              }
+               break;
+       case cpu_to_le16(0):
+               if (iftype != NL80211_IFTYPE_ADHOC &&
+@@ -646,7 +661,7 @@ int ieee80211_data_to_8023_exthdr(struct
+               break;
+       }
+-      if (likely(!is_amsdu &&
++      if (likely(!is_amsdu && iftype != NL80211_IFTYPE_MESH_POINT &&
+                  skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
+                  ieee80211_get_8023_tunnel_proto(&payload, &tmp.h_proto))) {
+               /* remove RFC1042 or Bridge-Tunnel encapsulation */
+@@ -722,7 +737,8 @@ __ieee80211_amsdu_copy_frag(struct sk_bu
+ static struct sk_buff *
+ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
+-                     int offset, int len, bool reuse_frag)
++                     int offset, int len, bool reuse_frag,
++                     int min_len)
+ {
+       struct sk_buff *frame;
+       int cur_len = len;
+@@ -736,7 +752,7 @@ __ieee80211_amsdu_copy(struct sk_buff *s
+        * in the stack later.
+        */
+       if (reuse_frag)
+-              cur_len = min_t(int, len, 32);
++              cur_len = min_t(int, len, min_len);
+       /*
+        * Allocate and reserve two bytes more for payload
+@@ -746,6 +762,7 @@ __ieee80211_amsdu_copy(struct sk_buff *s
+       if (!frame)
+               return NULL;
++      frame->priority = skb->priority;
+       skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
+       skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len);
+@@ -762,23 +779,37 @@ __ieee80211_amsdu_copy(struct sk_buff *s
+ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
+                             const u8 *addr, enum nl80211_iftype iftype,
+                             const unsigned int extra_headroom,
+-                            const u8 *check_da, const u8 *check_sa)
++                            const u8 *check_da, const u8 *check_sa,
++                            bool mesh_control)
+ {
+       unsigned int hlen = ALIGN(extra_headroom, 4);
+       struct sk_buff *frame = NULL;
+       int offset = 0, remaining;
+-      struct ethhdr eth;
++      struct {
++              struct ethhdr eth;
++              uint8_t flags;
++      } hdr;
+       bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
+       bool reuse_skb = false;
+       bool last = false;
++      int copy_len = sizeof(hdr.eth);
++
++      if (iftype == NL80211_IFTYPE_MESH_POINT)
++              copy_len = sizeof(hdr);
+       while (!last) {
+               unsigned int subframe_len;
+-              int len;
++              int len, mesh_len = 0;
+               u8 padding;
+-              skb_copy_bits(skb, offset, &eth, sizeof(eth));
+-              len = ntohs(eth.h_proto);
++              skb_copy_bits(skb, offset, &hdr, copy_len);
++              if (iftype == NL80211_IFTYPE_MESH_POINT)
++                      mesh_len = __ieee80211_get_mesh_hdrlen(hdr.flags);
++              if (mesh_control)
++                      len = le16_to_cpu(*(__le16 *)&hdr.eth.h_proto) + mesh_len;
++              else
++                      len = ntohs(hdr.eth.h_proto);
++
+               subframe_len = sizeof(struct ethhdr) + len;
+               padding = (4 - subframe_len) & 0x3;
+@@ -787,16 +818,16 @@ void ieee80211_amsdu_to_8023s(struct sk_
+               if (subframe_len > remaining)
+                       goto purge;
+               /* mitigate A-MSDU aggregation injection attacks */
+-              if (ether_addr_equal(eth.h_dest, rfc1042_header))
++              if (ether_addr_equal(hdr.eth.h_dest, rfc1042_header))
+                       goto purge;
+               offset += sizeof(struct ethhdr);
+               last = remaining <= subframe_len + padding;
+               /* FIXME: should we really accept multicast DA? */
+-              if ((check_da && !is_multicast_ether_addr(eth.h_dest) &&
+-                   !ether_addr_equal(check_da, eth.h_dest)) ||
+-                  (check_sa && !ether_addr_equal(check_sa, eth.h_source))) {
++              if ((check_da && !is_multicast_ether_addr(hdr.eth.h_dest) &&
++                   !ether_addr_equal(check_da, hdr.eth.h_dest)) ||
++                  (check_sa && !ether_addr_equal(check_sa, hdr.eth.h_source))) {
+                       offset += len + padding;
+                       continue;
+               }
+@@ -808,7 +839,7 @@ void ieee80211_amsdu_to_8023s(struct sk_
+                       reuse_skb = true;
+               } else {
+                       frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
+-                                                     reuse_frag);
++                                                     reuse_frag, 32 + mesh_len);
+                       if (!frame)
+                               goto purge;
+@@ -819,10 +850,11 @@ void ieee80211_amsdu_to_8023s(struct sk_
+               frame->dev = skb->dev;
+               frame->priority = skb->priority;
+-              if (likely(ieee80211_get_8023_tunnel_proto(frame->data, &eth.h_proto)))
++              if (likely(iftype != NL80211_IFTYPE_MESH_POINT &&
++                         ieee80211_get_8023_tunnel_proto(frame->data, &hdr.eth.h_proto)))
+                       skb_pull(frame, ETH_ALEN + 2);
+-              memcpy(skb_push(frame, sizeof(eth)), &eth, sizeof(eth));
++              memcpy(skb_push(frame, sizeof(hdr.eth)), &hdr.eth, sizeof(hdr.eth));
+               __skb_queue_tail(list, frame);
+       }
diff --git a/package/kernel/mac80211/patches/subsys/315-wifi-mac80211-fix-receiving-A-MSDU-frames-on-mesh-in.patch b/package/kernel/mac80211/patches/subsys/315-wifi-mac80211-fix-receiving-A-MSDU-frames-on-mesh-in.patch
deleted file mode 100644 (file)
index 6aec9bc..0000000
+++ /dev/null
@@ -1,753 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Tue, 6 Dec 2022 11:15:02 +0100
-Subject: [PATCH] wifi: mac80211: fix receiving A-MSDU frames on mesh
- interfaces
-
-The current mac80211 mesh A-MSDU receive path fails to parse A-MSDU packets
-on mesh interfaces, because it assumes that the Mesh Control field is always
-directly after the 802.11 header.
-802.11-2020 9.3.2.2.2 Figure 9-70 shows that the Mesh Control field is
-actually part of the A-MSDU subframe header.
-This makes more sense, since it allows packets for multiple different
-destinations to be included in the same A-MSDU, as long as RA and TID are
-still the same.
-Another issue is the fact that the A-MSDU subframe length field was apparently
-accidentally defined as little-endian in the standard.
-
-In order to fix this, the mesh forwarding path needs happen at a different
-point in the receive path.
-
-ieee80211_data_to_8023_exthdr is changed to ignore the mesh control field
-and leave it in after the ethernet header. This also affects the source/dest
-MAC address fields, which now in the case of mesh point to the mesh SA/DA.
-
-ieee80211_amsdu_to_8023s is changed to deal with the endian difference and
-to add the Mesh Control length to the subframe length, since it's not covered
-by the MSDU length field.
-
-With these changes, the mac80211 will get the same packet structure for
-converted regular data packets and unpacked A-MSDU subframes.
-
-The mesh forwarding checks are now only performed after the A-MSDU decap.
-For locally received packets, the Mesh Control header is stripped away.
-For forwarded packets, a new 802.11 header gets added.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
-+++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
-@@ -33,7 +33,7 @@ static int mwifiex_11n_dispatch_amsdu_pk
-               skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
-               ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
--                                       priv->wdev.iftype, 0, NULL, NULL);
-+                                       priv->wdev.iftype, 0, NULL, NULL, false);
-               while (!skb_queue_empty(&list)) {
-                       struct rx_packet_hdr *rx_hdr;
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -6208,11 +6208,36 @@ static inline int ieee80211_data_to_8023
-  * @extra_headroom: The hardware extra headroom for SKBs in the @list.
-  * @check_da: DA to check in the inner ethernet header, or NULL
-  * @check_sa: SA to check in the inner ethernet header, or NULL
-+ * @mesh_control: A-MSDU subframe header includes the mesh control field
-  */
- void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
-                             const u8 *addr, enum nl80211_iftype iftype,
-                             const unsigned int extra_headroom,
--                            const u8 *check_da, const u8 *check_sa);
-+                            const u8 *check_da, const u8 *check_sa,
-+                            bool mesh_control);
-+
-+/**
-+ * ieee80211_get_8023_tunnel_proto - get RFC1042 or bridge tunnel encap protocol
-+ *
-+ * Check for RFC1042 or bridge tunnel header and fetch the encapsulated
-+ * protocol.
-+ *
-+ * @hdr: pointer to the MSDU payload
-+ * @proto: destination pointer to store the protocol
-+ * Return: true if encapsulation was found
-+ */
-+bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto);
-+
-+/**
-+ * ieee80211_strip_8023_mesh_hdr - strip mesh header from converted 802.3 frames
-+ *
-+ * Strip the mesh header, which was left in by ieee80211_data_to_8023 as part
-+ * of the MSDU data. Also move any source/destination addresses from the mesh
-+ * header to the ethernet header (if present).
-+ *
-+ * @skb: The 802.3 frame with embedded mesh header
-+ */
-+int ieee80211_strip_8023_mesh_hdr(struct sk_buff *skb);
- /**
-  * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2720,6 +2720,174 @@ ieee80211_deliver_skb(struct ieee80211_r
-       }
- }
-+static ieee80211_rx_result
-+ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta,
-+                     struct sk_buff *skb)
-+{
-+#ifdef CPTCFG_MAC80211_MESH
-+      struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-+      struct ieee80211_local *local = sdata->local;
-+      uint16_t fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA;
-+      struct ieee80211_hdr hdr = {
-+              .frame_control = cpu_to_le16(fc)
-+      };
-+      struct ieee80211_hdr *fwd_hdr;
-+      struct ieee80211s_hdr *mesh_hdr;
-+      struct ieee80211_tx_info *info;
-+      struct sk_buff *fwd_skb;
-+      struct ethhdr *eth;
-+      bool multicast;
-+      int tailroom = 0;
-+      int hdrlen, mesh_hdrlen;
-+      u8 *qos;
-+
-+      if (!ieee80211_vif_is_mesh(&sdata->vif))
-+              return RX_CONTINUE;
-+
-+      if (!pskb_may_pull(skb, sizeof(*eth) + 6))
-+              return RX_DROP_MONITOR;
-+
-+      mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(*eth));
-+      mesh_hdrlen = ieee80211_get_mesh_hdrlen(mesh_hdr);
-+
-+      if (!pskb_may_pull(skb, sizeof(*eth) + mesh_hdrlen))
-+              return RX_DROP_MONITOR;
-+
-+      eth = (struct ethhdr *)skb->data;
-+      multicast = is_multicast_ether_addr(eth->h_dest);
-+
-+      mesh_hdr = (struct ieee80211s_hdr *)(eth + 1);
-+      if (!mesh_hdr->ttl)
-+              return RX_DROP_MONITOR;
-+
-+      /* frame is in RMC, don't forward */
-+      if (is_multicast_ether_addr(eth->h_dest) &&
-+          mesh_rmc_check(sdata, eth->h_source, mesh_hdr))
-+              return RX_DROP_MONITOR;
-+
-+      /* Frame has reached destination.  Don't forward */
-+      if (ether_addr_equal(sdata->vif.addr, eth->h_dest))
-+              goto rx_accept;
-+
-+      if (!ifmsh->mshcfg.dot11MeshForwarding) {
-+              if (is_multicast_ether_addr(eth->h_dest))
-+                      goto rx_accept;
-+
-+              return RX_DROP_MONITOR;
-+      }
-+
-+      /* forward packet */
-+      if (sdata->crypto_tx_tailroom_needed_cnt)
-+              tailroom = IEEE80211_ENCRYPT_TAILROOM;
-+
-+      if (!--mesh_hdr->ttl) {
-+              if (multicast)
-+                      goto rx_accept;
-+
-+              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl);
-+              return RX_DROP_MONITOR;
-+      }
-+
-+      if (mesh_hdr->flags & MESH_FLAGS_AE) {
-+              struct mesh_path *mppath;
-+              char *proxied_addr;
-+
-+              if (multicast)
-+                      proxied_addr = mesh_hdr->eaddr1;
-+              else if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
-+                      /* has_a4 already checked in ieee80211_rx_mesh_check */
-+                      proxied_addr = mesh_hdr->eaddr2;
-+              else
-+                      return RX_DROP_MONITOR;
-+
-+              rcu_read_lock();
-+              mppath = mpp_path_lookup(sdata, proxied_addr);
-+              if (!mppath) {
-+                      mpp_path_add(sdata, proxied_addr, eth->h_source);
-+              } else {
-+                      spin_lock_bh(&mppath->state_lock);
-+                      if (!ether_addr_equal(mppath->mpp, eth->h_source))
-+                              memcpy(mppath->mpp, eth->h_source, ETH_ALEN);
-+                      mppath->exp_time = jiffies;
-+                      spin_unlock_bh(&mppath->state_lock);
-+              }
-+              rcu_read_unlock();
-+      }
-+
-+      skb_set_queue_mapping(skb, ieee802_1d_to_ac[skb->priority]);
-+
-+      ieee80211_fill_mesh_addresses(&hdr, &hdr.frame_control,
-+                                    eth->h_dest, eth->h_source);
-+      hdrlen = ieee80211_hdrlen(hdr.frame_control);
-+      if (multicast) {
-+              int extra_head = sizeof(struct ieee80211_hdr) - sizeof(*eth);
-+
-+              fwd_skb = skb_copy_expand(skb, local->tx_headroom + extra_head +
-+                                             IEEE80211_ENCRYPT_HEADROOM,
-+                                        tailroom, GFP_ATOMIC);
-+              if (!fwd_skb)
-+                      goto rx_accept;
-+      } else {
-+              fwd_skb = skb;
-+              skb = NULL;
-+
-+              if (skb_cow_head(fwd_skb, hdrlen - sizeof(struct ethhdr)))
-+                      return RX_DROP_UNUSABLE;
-+      }
-+
-+      fwd_hdr = skb_push(fwd_skb, hdrlen - sizeof(struct ethhdr));
-+      memcpy(fwd_hdr, &hdr, hdrlen - 2);
-+      qos = ieee80211_get_qos_ctl(fwd_hdr);
-+      qos[0] = qos[1] = 0;
-+
-+      skb_reset_mac_header(fwd_skb);
-+      hdrlen += mesh_hdrlen;
-+      if (ieee80211_get_8023_tunnel_proto(fwd_skb->data + hdrlen,
-+                                          &fwd_skb->protocol))
-+              hdrlen += ETH_ALEN;
-+      else
-+              fwd_skb->protocol = htons(fwd_skb->len - hdrlen);
-+      skb_set_network_header(fwd_skb, hdrlen);
-+
-+      info = IEEE80211_SKB_CB(fwd_skb);
-+      memset(info, 0, sizeof(*info));
-+      info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
-+      info->control.vif = &sdata->vif;
-+      info->control.jiffies = jiffies;
-+      if (multicast) {
-+              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
-+              memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
-+              /* update power mode indication when forwarding */
-+              ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
-+      } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
-+              /* mesh power mode flags updated in mesh_nexthop_lookup */
-+              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
-+      } else {
-+              /* unable to resolve next hop */
-+              if (sta)
-+                      mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
-+                                         hdr.addr3, 0,
-+                                         WLAN_REASON_MESH_PATH_NOFORWARD,
-+                                         sta->sta.addr);
-+              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
-+              kfree_skb(fwd_skb);
-+              goto rx_accept;
-+      }
-+
-+      IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
-+      fwd_skb->dev = sdata->dev;
-+      ieee80211_add_pending_skb(local, fwd_skb);
-+
-+rx_accept:
-+      if (!skb)
-+              return RX_QUEUED;
-+
-+      ieee80211_strip_8023_mesh_hdr(skb);
-+#endif
-+
-+      return RX_CONTINUE;
-+}
-+
- static ieee80211_rx_result debug_noinline
- __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
- {
-@@ -2728,8 +2896,10 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       __le16 fc = hdr->frame_control;
-       struct sk_buff_head frame_list;
-+      static ieee80211_rx_result res;
-       struct ethhdr ethhdr;
-       const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
-+      bool mesh = false;
-       if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
-               check_da = NULL;
-@@ -2746,6 +2916,8 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
-                       break;
-               case NL80211_IFTYPE_MESH_POINT:
-                       check_sa = NULL;
-+                      check_da = NULL;
-+                      mesh = true;
-                       break;
-               default:
-                       break;
-@@ -2763,17 +2935,29 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
-       ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
-                                rx->sdata->vif.type,
-                                rx->local->hw.extra_tx_headroom,
--                               check_da, check_sa);
-+                               check_da, check_sa, mesh);
-       while (!skb_queue_empty(&frame_list)) {
-               rx->skb = __skb_dequeue(&frame_list);
--              if (!ieee80211_frame_allowed(rx, fc)) {
--                      dev_kfree_skb(rx->skb);
-+              res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
-+              switch (res) {
-+              case RX_QUEUED:
-                       continue;
-+              case RX_CONTINUE:
-+                      break;
-+              default:
-+                      goto free;
-               }
-+              if (!ieee80211_frame_allowed(rx, fc))
-+                      goto free;
-+
-               ieee80211_deliver_skb(rx);
-+              continue;
-+
-+free:
-+              dev_kfree_skb(rx->skb);
-       }
-       return RX_QUEUED;
-@@ -2806,6 +2990,8 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx
-                       if (!rx->sdata->u.mgd.use_4addr)
-                               return RX_DROP_UNUSABLE;
-                       break;
-+              case NL80211_IFTYPE_MESH_POINT:
-+                      break;
-               default:
-                       return RX_DROP_UNUSABLE;
-               }
-@@ -2834,155 +3020,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx
-       return __ieee80211_rx_h_amsdu(rx, 0);
- }
--#ifdef CPTCFG_MAC80211_MESH
--static ieee80211_rx_result
--ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
--{
--      struct ieee80211_hdr *fwd_hdr, *hdr;
--      struct ieee80211_tx_info *info;
--      struct ieee80211s_hdr *mesh_hdr;
--      struct sk_buff *skb = rx->skb, *fwd_skb;
--      struct ieee80211_local *local = rx->local;
--      struct ieee80211_sub_if_data *sdata = rx->sdata;
--      struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
--      u16 ac, q, hdrlen;
--      int tailroom = 0;
--
--      hdr = (struct ieee80211_hdr *) skb->data;
--      hdrlen = ieee80211_hdrlen(hdr->frame_control);
--
--      /* make sure fixed part of mesh header is there, also checks skb len */
--      if (!pskb_may_pull(rx->skb, hdrlen + 6))
--              return RX_DROP_MONITOR;
--
--      mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
--
--      /* make sure full mesh header is there, also checks skb len */
--      if (!pskb_may_pull(rx->skb,
--                         hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr)))
--              return RX_DROP_MONITOR;
--
--      /* reload pointers */
--      hdr = (struct ieee80211_hdr *) skb->data;
--      mesh_hdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
--
--      if (ieee80211_drop_unencrypted(rx, hdr->frame_control)) {
--              int offset = hdrlen + ieee80211_get_mesh_hdrlen(mesh_hdr) +
--                           sizeof(rfc1042_header);
--              __be16 ethertype;
--
--              if (!ether_addr_equal(hdr->addr1, rx->sdata->vif.addr) ||
--                  skb_copy_bits(rx->skb, offset, &ethertype, 2) != 0 ||
--                  ethertype != rx->sdata->control_port_protocol)
--                      return RX_DROP_MONITOR;
--      }
--
--      /* frame is in RMC, don't forward */
--      if (ieee80211_is_data(hdr->frame_control) &&
--          is_multicast_ether_addr(hdr->addr1) &&
--          mesh_rmc_check(rx->sdata, hdr->addr3, mesh_hdr))
--              return RX_DROP_MONITOR;
--
--      if (!ieee80211_is_data(hdr->frame_control))
--              return RX_CONTINUE;
--
--      if (!mesh_hdr->ttl)
--              return RX_DROP_MONITOR;
--
--      if (mesh_hdr->flags & MESH_FLAGS_AE) {
--              struct mesh_path *mppath;
--              char *proxied_addr;
--              char *mpp_addr;
--
--              if (is_multicast_ether_addr(hdr->addr1)) {
--                      mpp_addr = hdr->addr3;
--                      proxied_addr = mesh_hdr->eaddr1;
--              } else if ((mesh_hdr->flags & MESH_FLAGS_AE) ==
--                          MESH_FLAGS_AE_A5_A6) {
--                      /* has_a4 already checked in ieee80211_rx_mesh_check */
--                      mpp_addr = hdr->addr4;
--                      proxied_addr = mesh_hdr->eaddr2;
--              } else {
--                      return RX_DROP_MONITOR;
--              }
--
--              rcu_read_lock();
--              mppath = mpp_path_lookup(sdata, proxied_addr);
--              if (!mppath) {
--                      mpp_path_add(sdata, proxied_addr, mpp_addr);
--              } else {
--                      spin_lock_bh(&mppath->state_lock);
--                      if (!ether_addr_equal(mppath->mpp, mpp_addr))
--                              memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
--                      mppath->exp_time = jiffies;
--                      spin_unlock_bh(&mppath->state_lock);
--              }
--              rcu_read_unlock();
--      }
--
--      /* Frame has reached destination.  Don't forward */
--      if (!is_multicast_ether_addr(hdr->addr1) &&
--          ether_addr_equal(sdata->vif.addr, hdr->addr3))
--              return RX_CONTINUE;
--
--      ac = ieee802_1d_to_ac[skb->priority];
--      skb_set_queue_mapping(skb, ac);
--
--      if (!--mesh_hdr->ttl) {
--              if (!is_multicast_ether_addr(hdr->addr1))
--                      IEEE80211_IFSTA_MESH_CTR_INC(ifmsh,
--                                                   dropped_frames_ttl);
--              goto out;
--      }
--
--      if (!ifmsh->mshcfg.dot11MeshForwarding)
--              goto out;
--
--      if (sdata->crypto_tx_tailroom_needed_cnt)
--              tailroom = IEEE80211_ENCRYPT_TAILROOM;
--
--      fwd_skb = skb_copy_expand(skb, local->tx_headroom +
--                                     IEEE80211_ENCRYPT_HEADROOM,
--                                tailroom, GFP_ATOMIC);
--      if (!fwd_skb)
--              goto out;
--
--      fwd_skb->dev = sdata->dev;
--      fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
--      fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY);
--      info = IEEE80211_SKB_CB(fwd_skb);
--      memset(info, 0, sizeof(*info));
--      info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
--      info->control.vif = &rx->sdata->vif;
--      info->control.jiffies = jiffies;
--      if (is_multicast_ether_addr(fwd_hdr->addr1)) {
--              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_mcast);
--              memcpy(fwd_hdr->addr2, sdata->vif.addr, ETH_ALEN);
--              /* update power mode indication when forwarding */
--              ieee80211_mps_set_frame_flags(sdata, NULL, fwd_hdr);
--      } else if (!mesh_nexthop_lookup(sdata, fwd_skb)) {
--              /* mesh power mode flags updated in mesh_nexthop_lookup */
--              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
--      } else {
--              /* unable to resolve next hop */
--              mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,
--                                 fwd_hdr->addr3, 0,
--                                 WLAN_REASON_MESH_PATH_NOFORWARD,
--                                 fwd_hdr->addr2);
--              IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
--              kfree_skb(fwd_skb);
--              return RX_DROP_MONITOR;
--      }
--
--      IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
--      ieee80211_add_pending_skb(local, fwd_skb);
-- out:
--      if (is_multicast_ether_addr(hdr->addr1))
--              return RX_CONTINUE;
--      return RX_DROP_MONITOR;
--}
--#endif
--
- static ieee80211_rx_result debug_noinline
- ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
- {
-@@ -2991,6 +3028,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_
-       struct net_device *dev = sdata->dev;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
-       __le16 fc = hdr->frame_control;
-+      static ieee80211_rx_result res;
-       bool port_control;
-       int err;
-@@ -3017,6 +3055,10 @@ ieee80211_rx_h_data(struct ieee80211_rx_
-       if (unlikely(err))
-               return RX_DROP_UNUSABLE;
-+      res = ieee80211_rx_mesh_data(rx->sdata, rx->sta, rx->skb);
-+      if (res != RX_CONTINUE)
-+              return res;
-+
-       if (!ieee80211_frame_allowed(rx, fc))
-               return RX_DROP_MONITOR;
-@@ -3987,10 +4029,6 @@ static void ieee80211_rx_handlers(struct
-               CALL_RXH(ieee80211_rx_h_defragment);
-               CALL_RXH(ieee80211_rx_h_michael_mic_verify);
-               /* must be after MMIC verify so header is counted in MPDU mic */
--#ifdef CPTCFG_MAC80211_MESH
--              if (ieee80211_vif_is_mesh(&rx->sdata->vif))
--                      CALL_RXH(ieee80211_rx_h_mesh_fwding);
--#endif
-               CALL_RXH(ieee80211_rx_h_amsdu);
-               CALL_RXH(ieee80211_rx_h_data);
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -542,7 +542,7 @@ unsigned int ieee80211_get_mesh_hdrlen(s
- }
- EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
--static bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto)
-+bool ieee80211_get_8023_tunnel_proto(const void *hdr, __be16 *proto)
- {
-       const __be16 *hdr_proto = hdr + ETH_ALEN;
-@@ -556,6 +556,49 @@ static bool ieee80211_get_8023_tunnel_pr
-       return true;
- }
-+EXPORT_SYMBOL(ieee80211_get_8023_tunnel_proto);
-+
-+int ieee80211_strip_8023_mesh_hdr(struct sk_buff *skb)
-+{
-+      const void *mesh_addr;
-+      struct {
-+              struct ethhdr eth;
-+              u8 flags;
-+      } payload;
-+      int hdrlen;
-+      int ret;
-+
-+      ret = skb_copy_bits(skb, 0, &payload, sizeof(payload));
-+      if (ret)
-+              return ret;
-+
-+      hdrlen = sizeof(payload.eth) + __ieee80211_get_mesh_hdrlen(payload.flags);
-+
-+      if (likely(pskb_may_pull(skb, hdrlen + 8) &&
-+                 ieee80211_get_8023_tunnel_proto(skb->data + hdrlen,
-+                                                 &payload.eth.h_proto)))
-+              hdrlen += ETH_ALEN + 2;
-+      else if (!pskb_may_pull(skb, hdrlen))
-+              return -EINVAL;
-+
-+      mesh_addr = skb->data + sizeof(payload.eth) + ETH_ALEN;
-+      switch (payload.flags & MESH_FLAGS_AE) {
-+      case MESH_FLAGS_AE_A4:
-+              memcpy(&payload.eth.h_source, mesh_addr, ETH_ALEN);
-+              break;
-+      case MESH_FLAGS_AE_A5_A6:
-+              memcpy(&payload.eth.h_dest, mesh_addr, 2 * ETH_ALEN);
-+              break;
-+      default:
-+              break;
-+      }
-+
-+      pskb_pull(skb, hdrlen - sizeof(payload.eth));
-+      memcpy(skb->data, &payload.eth, sizeof(payload.eth));
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL(ieee80211_strip_8023_mesh_hdr);
- int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
-                                 const u8 *addr, enum nl80211_iftype iftype,
-@@ -568,7 +611,6 @@ int ieee80211_data_to_8023_exthdr(struct
-       } payload;
-       struct ethhdr tmp;
-       u16 hdrlen;
--      u8 mesh_flags = 0;
-       if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
-               return -1;
-@@ -589,12 +631,6 @@ int ieee80211_data_to_8023_exthdr(struct
-       memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
-       memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
--      if (iftype == NL80211_IFTYPE_MESH_POINT &&
--          skb_copy_bits(skb, hdrlen, &mesh_flags, 1) < 0)
--              return -1;
--
--      mesh_flags &= MESH_FLAGS_AE;
--
-       switch (hdr->frame_control &
-               cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
-       case cpu_to_le16(IEEE80211_FCTL_TODS):
-@@ -608,17 +644,6 @@ int ieee80211_data_to_8023_exthdr(struct
-                            iftype != NL80211_IFTYPE_AP_VLAN &&
-                            iftype != NL80211_IFTYPE_STATION))
-                       return -1;
--              if (iftype == NL80211_IFTYPE_MESH_POINT) {
--                      if (mesh_flags == MESH_FLAGS_AE_A4)
--                              return -1;
--                      if (mesh_flags == MESH_FLAGS_AE_A5_A6 &&
--                          skb_copy_bits(skb, hdrlen +
--                                        offsetof(struct ieee80211s_hdr, eaddr1),
--                                        tmp.h_dest, 2 * ETH_ALEN) < 0)
--                              return -1;
--
--                      hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
--              }
-               break;
-       case cpu_to_le16(IEEE80211_FCTL_FROMDS):
-               if ((iftype != NL80211_IFTYPE_STATION &&
-@@ -627,16 +652,6 @@ int ieee80211_data_to_8023_exthdr(struct
-                   (is_multicast_ether_addr(tmp.h_dest) &&
-                    ether_addr_equal(tmp.h_source, addr)))
-                       return -1;
--              if (iftype == NL80211_IFTYPE_MESH_POINT) {
--                      if (mesh_flags == MESH_FLAGS_AE_A5_A6)
--                              return -1;
--                      if (mesh_flags == MESH_FLAGS_AE_A4 &&
--                          skb_copy_bits(skb, hdrlen +
--                                        offsetof(struct ieee80211s_hdr, eaddr1),
--                                        tmp.h_source, ETH_ALEN) < 0)
--                              return -1;
--                      hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
--              }
-               break;
-       case cpu_to_le16(0):
-               if (iftype != NL80211_IFTYPE_ADHOC &&
-@@ -646,7 +661,7 @@ int ieee80211_data_to_8023_exthdr(struct
-               break;
-       }
--      if (likely(!is_amsdu &&
-+      if (likely(!is_amsdu && iftype != NL80211_IFTYPE_MESH_POINT &&
-                  skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
-                  ieee80211_get_8023_tunnel_proto(&payload, &tmp.h_proto))) {
-               /* remove RFC1042 or Bridge-Tunnel encapsulation */
-@@ -722,7 +737,8 @@ __ieee80211_amsdu_copy_frag(struct sk_bu
- static struct sk_buff *
- __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
--                     int offset, int len, bool reuse_frag)
-+                     int offset, int len, bool reuse_frag,
-+                     int min_len)
- {
-       struct sk_buff *frame;
-       int cur_len = len;
-@@ -736,7 +752,7 @@ __ieee80211_amsdu_copy(struct sk_buff *s
-        * in the stack later.
-        */
-       if (reuse_frag)
--              cur_len = min_t(int, len, 32);
-+              cur_len = min_t(int, len, min_len);
-       /*
-        * Allocate and reserve two bytes more for payload
-@@ -746,6 +762,7 @@ __ieee80211_amsdu_copy(struct sk_buff *s
-       if (!frame)
-               return NULL;
-+      frame->priority = skb->priority;
-       skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
-       skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len);
-@@ -762,23 +779,37 @@ __ieee80211_amsdu_copy(struct sk_buff *s
- void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
-                             const u8 *addr, enum nl80211_iftype iftype,
-                             const unsigned int extra_headroom,
--                            const u8 *check_da, const u8 *check_sa)
-+                            const u8 *check_da, const u8 *check_sa,
-+                            bool mesh_control)
- {
-       unsigned int hlen = ALIGN(extra_headroom, 4);
-       struct sk_buff *frame = NULL;
-       int offset = 0, remaining;
--      struct ethhdr eth;
-+      struct {
-+              struct ethhdr eth;
-+              uint8_t flags;
-+      } hdr;
-       bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
-       bool reuse_skb = false;
-       bool last = false;
-+      int copy_len = sizeof(hdr.eth);
-+
-+      if (iftype == NL80211_IFTYPE_MESH_POINT)
-+              copy_len = sizeof(hdr);
-       while (!last) {
-               unsigned int subframe_len;
--              int len;
-+              int len, mesh_len = 0;
-               u8 padding;
--              skb_copy_bits(skb, offset, &eth, sizeof(eth));
--              len = ntohs(eth.h_proto);
-+              skb_copy_bits(skb, offset, &hdr, copy_len);
-+              if (iftype == NL80211_IFTYPE_MESH_POINT)
-+                      mesh_len = __ieee80211_get_mesh_hdrlen(hdr.flags);
-+              if (mesh_control)
-+                      len = le16_to_cpu(*(__le16 *)&hdr.eth.h_proto) + mesh_len;
-+              else
-+                      len = ntohs(hdr.eth.h_proto);
-+
-               subframe_len = sizeof(struct ethhdr) + len;
-               padding = (4 - subframe_len) & 0x3;
-@@ -787,16 +818,16 @@ void ieee80211_amsdu_to_8023s(struct sk_
-               if (subframe_len > remaining)
-                       goto purge;
-               /* mitigate A-MSDU aggregation injection attacks */
--              if (ether_addr_equal(eth.h_dest, rfc1042_header))
-+              if (ether_addr_equal(hdr.eth.h_dest, rfc1042_header))
-                       goto purge;
-               offset += sizeof(struct ethhdr);
-               last = remaining <= subframe_len + padding;
-               /* FIXME: should we really accept multicast DA? */
--              if ((check_da && !is_multicast_ether_addr(eth.h_dest) &&
--                   !ether_addr_equal(check_da, eth.h_dest)) ||
--                  (check_sa && !ether_addr_equal(check_sa, eth.h_source))) {
-+              if ((check_da && !is_multicast_ether_addr(hdr.eth.h_dest) &&
-+                   !ether_addr_equal(check_da, hdr.eth.h_dest)) ||
-+                  (check_sa && !ether_addr_equal(check_sa, hdr.eth.h_source))) {
-                       offset += len + padding;
-                       continue;
-               }
-@@ -808,7 +839,7 @@ void ieee80211_amsdu_to_8023s(struct sk_
-                       reuse_skb = true;
-               } else {
-                       frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
--                                                     reuse_frag);
-+                                                     reuse_frag, 32 + mesh_len);
-                       if (!frame)
-                               goto purge;
-@@ -819,10 +850,11 @@ void ieee80211_amsdu_to_8023s(struct sk_
-               frame->dev = skb->dev;
-               frame->priority = skb->priority;
--              if (likely(ieee80211_get_8023_tunnel_proto(frame->data, &eth.h_proto)))
-+              if (likely(iftype != NL80211_IFTYPE_MESH_POINT &&
-+                         ieee80211_get_8023_tunnel_proto(frame->data, &hdr.eth.h_proto)))
-                       skb_pull(frame, ETH_ALEN + 2);
--              memcpy(skb_push(frame, sizeof(eth)), &eth, sizeof(eth));
-+              memcpy(skb_push(frame, sizeof(hdr.eth)), &hdr.eth, sizeof(hdr.eth));
-               __skb_queue_tail(list, frame);
-       }
diff --git a/package/kernel/mac80211/patches/subsys/316-v6.3-wifi-mac80211-add-a-workaround-for-receiving-non-sta.patch b/package/kernel/mac80211/patches/subsys/316-v6.3-wifi-mac80211-add-a-workaround-for-receiving-non-sta.patch
new file mode 100644 (file)
index 0000000..6dc98ae
--- /dev/null
@@ -0,0 +1,145 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 9 Dec 2022 21:15:04 +0100
+Subject: [PATCH] wifi: mac80211: add a workaround for receiving
+ non-standard mesh A-MSDU
+
+At least ath10k and ath11k supported hardware (maybe more) does not implement
+mesh A-MSDU aggregation in a standard compliant way.
+802.11-2020 9.3.2.2.2 declares that the Mesh Control field is part of the
+A-MSDU header. As such, its length must not be included in the subframe
+length field.
+Hardware affected by this bug treats the mesh control field as part of the
+MSDU data and sets the length accordingly.
+In order to avoid packet loss, keep track of which stations are affected
+by this and take it into account when converting A-MSDU to 802.3 + mesh control
+packets.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -6194,6 +6194,19 @@ static inline int ieee80211_data_to_8023
+ }
+ /**
++ * ieee80211_is_valid_amsdu - check if subframe lengths of an A-MSDU are valid
++ *
++ * This is used to detect non-standard A-MSDU frames, e.g. the ones generated
++ * by ath10k and ath11k, where the subframe length includes the length of the
++ * mesh control field.
++ *
++ * @skb: The input A-MSDU frame without any headers.
++ * @mesh_hdr: use standard compliant mesh A-MSDU subframe header
++ * Returns: true if subframe header lengths are valid for the @mesh_hdr mode
++ */
++bool ieee80211_is_valid_amsdu(struct sk_buff *skb, bool mesh_hdr);
++
++/**
+  * ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
+  *
+  * Decode an IEEE 802.11 A-MSDU and convert it to a list of 802.3 frames.
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2899,7 +2899,6 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
+       static ieee80211_rx_result res;
+       struct ethhdr ethhdr;
+       const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
+-      bool mesh = false;
+       if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
+               check_da = NULL;
+@@ -2917,7 +2916,6 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
+               case NL80211_IFTYPE_MESH_POINT:
+                       check_sa = NULL;
+                       check_da = NULL;
+-                      mesh = true;
+                       break;
+               default:
+                       break;
+@@ -2932,10 +2930,21 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
+                                         data_offset, true))
+               return RX_DROP_UNUSABLE;
++      if (rx->sta && rx->sta->amsdu_mesh_control < 0) {
++              bool valid_std = ieee80211_is_valid_amsdu(skb, true);
++              bool valid_nonstd = ieee80211_is_valid_amsdu(skb, false);
++
++              if (valid_std && !valid_nonstd)
++                      rx->sta->amsdu_mesh_control = 1;
++              else if (valid_nonstd && !valid_std)
++                      rx->sta->amsdu_mesh_control = 0;
++      }
++
+       ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
+                                rx->sdata->vif.type,
+                                rx->local->hw.extra_tx_headroom,
+-                               check_da, check_sa, mesh);
++                               check_da, check_sa,
++                               rx->sta->amsdu_mesh_control);
+       while (!skb_queue_empty(&frame_list)) {
+               rx->skb = __skb_dequeue(&frame_list);
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -591,6 +591,9 @@ __sta_info_alloc(struct ieee80211_sub_if
+       sta->sta_state = IEEE80211_STA_NONE;
++      if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
++              sta->amsdu_mesh_control = -1;
++
+       /* Mark TID as unreserved */
+       sta->reserved_tid = IEEE80211_TID_UNRESERVED;
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -702,6 +702,7 @@ struct sta_info {
+       struct codel_params cparams;
+       u8 reserved_tid;
++      s8 amsdu_mesh_control;
+       struct cfg80211_chan_def tdls_chandef;
+--- a/net/wireless/util.c
++++ b/net/wireless/util.c
+@@ -776,6 +776,38 @@ __ieee80211_amsdu_copy(struct sk_buff *s
+       return frame;
+ }
++bool ieee80211_is_valid_amsdu(struct sk_buff *skb, bool mesh_hdr)
++{
++      int offset = 0, remaining, subframe_len, padding;
++
++      for (offset = 0; offset < skb->len; offset += subframe_len + padding) {
++              struct {
++                  __be16 len;
++                  u8 mesh_flags;
++              } hdr;
++              u16 len;
++
++              if (skb_copy_bits(skb, offset + 2 * ETH_ALEN, &hdr, sizeof(hdr)) < 0)
++                      return false;
++
++              if (mesh_hdr)
++                      len = le16_to_cpu(*(__le16 *)&hdr.len) +
++                            __ieee80211_get_mesh_hdrlen(hdr.mesh_flags);
++              else
++                      len = ntohs(hdr.len);
++
++              subframe_len = sizeof(struct ethhdr) + len;
++              padding = (4 - subframe_len) & 0x3;
++              remaining = skb->len - offset;
++
++              if (subframe_len > remaining)
++                      return false;
++      }
++
++      return true;
++}
++EXPORT_SYMBOL(ieee80211_is_valid_amsdu);
++
+ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
+                             const u8 *addr, enum nl80211_iftype iftype,
+                             const unsigned int extra_headroom,
diff --git a/package/kernel/mac80211/patches/subsys/316-wifi-mac80211-add-a-workaround-for-receiving-non-sta.patch b/package/kernel/mac80211/patches/subsys/316-wifi-mac80211-add-a-workaround-for-receiving-non-sta.patch
deleted file mode 100644 (file)
index 6dc98ae..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 9 Dec 2022 21:15:04 +0100
-Subject: [PATCH] wifi: mac80211: add a workaround for receiving
- non-standard mesh A-MSDU
-
-At least ath10k and ath11k supported hardware (maybe more) does not implement
-mesh A-MSDU aggregation in a standard compliant way.
-802.11-2020 9.3.2.2.2 declares that the Mesh Control field is part of the
-A-MSDU header. As such, its length must not be included in the subframe
-length field.
-Hardware affected by this bug treats the mesh control field as part of the
-MSDU data and sets the length accordingly.
-In order to avoid packet loss, keep track of which stations are affected
-by this and take it into account when converting A-MSDU to 802.3 + mesh control
-packets.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/include/net/cfg80211.h
-+++ b/include/net/cfg80211.h
-@@ -6194,6 +6194,19 @@ static inline int ieee80211_data_to_8023
- }
- /**
-+ * ieee80211_is_valid_amsdu - check if subframe lengths of an A-MSDU are valid
-+ *
-+ * This is used to detect non-standard A-MSDU frames, e.g. the ones generated
-+ * by ath10k and ath11k, where the subframe length includes the length of the
-+ * mesh control field.
-+ *
-+ * @skb: The input A-MSDU frame without any headers.
-+ * @mesh_hdr: use standard compliant mesh A-MSDU subframe header
-+ * Returns: true if subframe header lengths are valid for the @mesh_hdr mode
-+ */
-+bool ieee80211_is_valid_amsdu(struct sk_buff *skb, bool mesh_hdr);
-+
-+/**
-  * ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
-  *
-  * Decode an IEEE 802.11 A-MSDU and convert it to a list of 802.3 frames.
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2899,7 +2899,6 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
-       static ieee80211_rx_result res;
-       struct ethhdr ethhdr;
-       const u8 *check_da = ethhdr.h_dest, *check_sa = ethhdr.h_source;
--      bool mesh = false;
-       if (unlikely(ieee80211_has_a4(hdr->frame_control))) {
-               check_da = NULL;
-@@ -2917,7 +2916,6 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
-               case NL80211_IFTYPE_MESH_POINT:
-                       check_sa = NULL;
-                       check_da = NULL;
--                      mesh = true;
-                       break;
-               default:
-                       break;
-@@ -2932,10 +2930,21 @@ __ieee80211_rx_h_amsdu(struct ieee80211_
-                                         data_offset, true))
-               return RX_DROP_UNUSABLE;
-+      if (rx->sta && rx->sta->amsdu_mesh_control < 0) {
-+              bool valid_std = ieee80211_is_valid_amsdu(skb, true);
-+              bool valid_nonstd = ieee80211_is_valid_amsdu(skb, false);
-+
-+              if (valid_std && !valid_nonstd)
-+                      rx->sta->amsdu_mesh_control = 1;
-+              else if (valid_nonstd && !valid_std)
-+                      rx->sta->amsdu_mesh_control = 0;
-+      }
-+
-       ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
-                                rx->sdata->vif.type,
-                                rx->local->hw.extra_tx_headroom,
--                               check_da, check_sa, mesh);
-+                               check_da, check_sa,
-+                               rx->sta->amsdu_mesh_control);
-       while (!skb_queue_empty(&frame_list)) {
-               rx->skb = __skb_dequeue(&frame_list);
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -591,6 +591,9 @@ __sta_info_alloc(struct ieee80211_sub_if
-       sta->sta_state = IEEE80211_STA_NONE;
-+      if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
-+              sta->amsdu_mesh_control = -1;
-+
-       /* Mark TID as unreserved */
-       sta->reserved_tid = IEEE80211_TID_UNRESERVED;
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -702,6 +702,7 @@ struct sta_info {
-       struct codel_params cparams;
-       u8 reserved_tid;
-+      s8 amsdu_mesh_control;
-       struct cfg80211_chan_def tdls_chandef;
---- a/net/wireless/util.c
-+++ b/net/wireless/util.c
-@@ -776,6 +776,38 @@ __ieee80211_amsdu_copy(struct sk_buff *s
-       return frame;
- }
-+bool ieee80211_is_valid_amsdu(struct sk_buff *skb, bool mesh_hdr)
-+{
-+      int offset = 0, remaining, subframe_len, padding;
-+
-+      for (offset = 0; offset < skb->len; offset += subframe_len + padding) {
-+              struct {
-+                  __be16 len;
-+                  u8 mesh_flags;
-+              } hdr;
-+              u16 len;
-+
-+              if (skb_copy_bits(skb, offset + 2 * ETH_ALEN, &hdr, sizeof(hdr)) < 0)
-+                      return false;
-+
-+              if (mesh_hdr)
-+                      len = le16_to_cpu(*(__le16 *)&hdr.len) +
-+                            __ieee80211_get_mesh_hdrlen(hdr.mesh_flags);
-+              else
-+                      len = ntohs(hdr.len);
-+
-+              subframe_len = sizeof(struct ethhdr) + len;
-+              padding = (4 - subframe_len) & 0x3;
-+              remaining = skb->len - offset;
-+
-+              if (subframe_len > remaining)
-+                      return false;
-+      }
-+
-+      return true;
-+}
-+EXPORT_SYMBOL(ieee80211_is_valid_amsdu);
-+
- void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
-                             const u8 *addr, enum nl80211_iftype iftype,
-                             const unsigned int extra_headroom,
diff --git a/package/kernel/mac80211/patches/subsys/323-v6.3-wifi-mac80211-Add-VHT-MU-MIMO-related-flags-in-ieee8.patch b/package/kernel/mac80211/patches/subsys/323-v6.3-wifi-mac80211-Add-VHT-MU-MIMO-related-flags-in-ieee8.patch
new file mode 100644 (file)
index 0000000..2310593
--- /dev/null
@@ -0,0 +1,68 @@
+From: Muna Sinada <quic_msinada@quicinc.com>
+Date: Wed, 5 Oct 2022 14:54:45 -0700
+Subject: [PATCH] wifi: mac80211: Add VHT MU-MIMO related flags in
+ ieee80211_bss_conf
+
+Adding flags for SU Beamformer, SU Beamformee, MU Beamformer and
+MU Beamformee for VHT. This is utilized to pass MU-MIMO
+configurations from user space to driver in AP mode.
+
+Signed-off-by: Muna Sinada <quic_msinada@quicinc.com>
+Link: https://lore.kernel.org/r/1665006886-23874-1-git-send-email-quic_msinada@quicinc.com
+[fixed indentation, removed redundant !!]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -653,6 +653,14 @@ struct ieee80211_fils_discovery {
+  *    write-protected by sdata_lock and local->mtx so holding either is fine
+  *    for read access.
+  * @color_change_color: the bss color that will be used after the change.
++ * @vht_su_beamformer: in AP mode, does this BSS support operation as an VHT SU
++ *    beamformer
++ * @vht_su_beamformee: in AP mode, does this BSS support operation as an VHT SU
++ *    beamformee
++ * @vht_mu_beamformer: in AP mode, does this BSS support operation as an VHT MU
++ *    beamformer
++ * @vht_mu_beamformee: in AP mode, does this BSS support operation as an VHT MU
++ *    beamformee
+  */
+ struct ieee80211_bss_conf {
+       const u8 *bssid;
+@@ -726,6 +734,11 @@ struct ieee80211_bss_conf {
+       bool color_change_active;
+       u8 color_change_color;
++
++      bool vht_su_beamformer;
++      bool vht_su_beamformee;
++      bool vht_mu_beamformer;
++      bool vht_mu_beamformee;
+ };
+ /**
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -1251,6 +1251,21 @@ static int ieee80211_start_ap(struct wip
+       prev_beacon_int = link_conf->beacon_int;
+       link_conf->beacon_int = params->beacon_interval;
++      if (params->vht_cap) {
++              link_conf->vht_su_beamformer =
++                      params->vht_cap->vht_cap_info &
++                              cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
++              link_conf->vht_su_beamformee =
++                      params->vht_cap->vht_cap_info &
++                              cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
++              link_conf->vht_mu_beamformer =
++                      params->vht_cap->vht_cap_info &
++                              cpu_to_le32(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
++              link_conf->vht_mu_beamformee =
++                      params->vht_cap->vht_cap_info &
++                              cpu_to_le32(IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
++      }
++
+       if (params->he_cap && params->he_oper) {
+               link_conf->he_support = true;
+               link_conf->htc_trig_based_pkt_ext =
diff --git a/package/kernel/mac80211/patches/subsys/323-wifi-mac80211-Add-VHT-MU-MIMO-related-flags-in-ieee8.patch b/package/kernel/mac80211/patches/subsys/323-wifi-mac80211-Add-VHT-MU-MIMO-related-flags-in-ieee8.patch
deleted file mode 100644 (file)
index 2310593..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-From: Muna Sinada <quic_msinada@quicinc.com>
-Date: Wed, 5 Oct 2022 14:54:45 -0700
-Subject: [PATCH] wifi: mac80211: Add VHT MU-MIMO related flags in
- ieee80211_bss_conf
-
-Adding flags for SU Beamformer, SU Beamformee, MU Beamformer and
-MU Beamformee for VHT. This is utilized to pass MU-MIMO
-configurations from user space to driver in AP mode.
-
-Signed-off-by: Muna Sinada <quic_msinada@quicinc.com>
-Link: https://lore.kernel.org/r/1665006886-23874-1-git-send-email-quic_msinada@quicinc.com
-[fixed indentation, removed redundant !!]
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -653,6 +653,14 @@ struct ieee80211_fils_discovery {
-  *    write-protected by sdata_lock and local->mtx so holding either is fine
-  *    for read access.
-  * @color_change_color: the bss color that will be used after the change.
-+ * @vht_su_beamformer: in AP mode, does this BSS support operation as an VHT SU
-+ *    beamformer
-+ * @vht_su_beamformee: in AP mode, does this BSS support operation as an VHT SU
-+ *    beamformee
-+ * @vht_mu_beamformer: in AP mode, does this BSS support operation as an VHT MU
-+ *    beamformer
-+ * @vht_mu_beamformee: in AP mode, does this BSS support operation as an VHT MU
-+ *    beamformee
-  */
- struct ieee80211_bss_conf {
-       const u8 *bssid;
-@@ -726,6 +734,11 @@ struct ieee80211_bss_conf {
-       bool color_change_active;
-       u8 color_change_color;
-+
-+      bool vht_su_beamformer;
-+      bool vht_su_beamformee;
-+      bool vht_mu_beamformer;
-+      bool vht_mu_beamformee;
- };
- /**
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -1251,6 +1251,21 @@ static int ieee80211_start_ap(struct wip
-       prev_beacon_int = link_conf->beacon_int;
-       link_conf->beacon_int = params->beacon_interval;
-+      if (params->vht_cap) {
-+              link_conf->vht_su_beamformer =
-+                      params->vht_cap->vht_cap_info &
-+                              cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
-+              link_conf->vht_su_beamformee =
-+                      params->vht_cap->vht_cap_info &
-+                              cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
-+              link_conf->vht_mu_beamformer =
-+                      params->vht_cap->vht_cap_info &
-+                              cpu_to_le32(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
-+              link_conf->vht_mu_beamformee =
-+                      params->vht_cap->vht_cap_info &
-+                              cpu_to_le32(IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
-+      }
-+
-       if (params->he_cap && params->he_oper) {
-               link_conf->he_support = true;
-               link_conf->htc_trig_based_pkt_ext =
diff --git a/package/kernel/mac80211/patches/subsys/324-v6.3-wifi-mac80211-Add-HE-MU-MIMO-related-flags-in-ieee80.patch b/package/kernel/mac80211/patches/subsys/324-v6.3-wifi-mac80211-Add-HE-MU-MIMO-related-flags-in-ieee80.patch
new file mode 100644 (file)
index 0000000..a3c4453
--- /dev/null
@@ -0,0 +1,68 @@
+From: Muna Sinada <quic_msinada@quicinc.com>
+Date: Wed, 5 Oct 2022 14:54:46 -0700
+Subject: [PATCH] wifi: mac80211: Add HE MU-MIMO related flags in
+ ieee80211_bss_conf
+
+Adding flags for SU Beamformer, SU Beamformee, MU Beamformer and Full
+Bandwidth UL MU-MIMO for HE. This is utilized to pass MU-MIMO
+configurations from user space to driver in AP mode.
+
+Signed-off-by: Muna Sinada <quic_msinada@quicinc.com>
+Link: https://lore.kernel.org/r/1665006886-23874-2-git-send-email-quic_msinada@quicinc.com
+[fixed indentation, removed redundant !!]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -661,6 +661,15 @@ struct ieee80211_fils_discovery {
+  *    beamformer
+  * @vht_mu_beamformee: in AP mode, does this BSS support operation as an VHT MU
+  *    beamformee
++ * @he_su_beamformer: in AP-mode, does this BSS support operation as an HE SU
++ *    beamformer
++ * @he_su_beamformee: in AP-mode, does this BSS support operation as an HE SU
++ *    beamformee
++ * @he_mu_beamformer: in AP-mode, does this BSS support operation as an HE MU
++ *    beamformer
++ * @he_full_ul_mumimo: does this BSS support the reception (AP) or transmission
++ *    (non-AP STA) of an HE TB PPDU on an RU that spans the entire PPDU
++ *    bandwidth
+  */
+ struct ieee80211_bss_conf {
+       const u8 *bssid;
+@@ -739,6 +748,10 @@ struct ieee80211_bss_conf {
+       bool vht_su_beamformee;
+       bool vht_mu_beamformer;
+       bool vht_mu_beamformee;
++      bool he_su_beamformer;
++      bool he_su_beamformee;
++      bool he_mu_beamformer;
++      bool he_full_ul_mumimo;
+ };
+ /**
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -1280,6 +1280,21 @@ static int ieee80211_start_ap(struct wip
+                       changed |= BSS_CHANGED_HE_BSS_COLOR;
+       }
++      if (params->he_cap) {
++              link_conf->he_su_beamformer =
++                      params->he_cap->phy_cap_info[3] &
++                              IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
++              link_conf->he_su_beamformee =
++                      params->he_cap->phy_cap_info[4] &
++                              IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE;
++              link_conf->he_mu_beamformer =
++                      params->he_cap->phy_cap_info[4] &
++                              IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
++              link_conf->he_full_ul_mumimo =
++                      params->he_cap->phy_cap_info[2] &
++                              IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO;
++      }
++
+       if (sdata->vif.type == NL80211_IFTYPE_AP &&
+           params->mbssid_config.tx_wdev) {
+               err = ieee80211_set_ap_mbssid_options(sdata,
diff --git a/package/kernel/mac80211/patches/subsys/324-wifi-mac80211-Add-HE-MU-MIMO-related-flags-in-ieee80.patch b/package/kernel/mac80211/patches/subsys/324-wifi-mac80211-Add-HE-MU-MIMO-related-flags-in-ieee80.patch
deleted file mode 100644 (file)
index a3c4453..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-From: Muna Sinada <quic_msinada@quicinc.com>
-Date: Wed, 5 Oct 2022 14:54:46 -0700
-Subject: [PATCH] wifi: mac80211: Add HE MU-MIMO related flags in
- ieee80211_bss_conf
-
-Adding flags for SU Beamformer, SU Beamformee, MU Beamformer and Full
-Bandwidth UL MU-MIMO for HE. This is utilized to pass MU-MIMO
-configurations from user space to driver in AP mode.
-
-Signed-off-by: Muna Sinada <quic_msinada@quicinc.com>
-Link: https://lore.kernel.org/r/1665006886-23874-2-git-send-email-quic_msinada@quicinc.com
-[fixed indentation, removed redundant !!]
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -661,6 +661,15 @@ struct ieee80211_fils_discovery {
-  *    beamformer
-  * @vht_mu_beamformee: in AP mode, does this BSS support operation as an VHT MU
-  *    beamformee
-+ * @he_su_beamformer: in AP-mode, does this BSS support operation as an HE SU
-+ *    beamformer
-+ * @he_su_beamformee: in AP-mode, does this BSS support operation as an HE SU
-+ *    beamformee
-+ * @he_mu_beamformer: in AP-mode, does this BSS support operation as an HE MU
-+ *    beamformer
-+ * @he_full_ul_mumimo: does this BSS support the reception (AP) or transmission
-+ *    (non-AP STA) of an HE TB PPDU on an RU that spans the entire PPDU
-+ *    bandwidth
-  */
- struct ieee80211_bss_conf {
-       const u8 *bssid;
-@@ -739,6 +748,10 @@ struct ieee80211_bss_conf {
-       bool vht_su_beamformee;
-       bool vht_mu_beamformer;
-       bool vht_mu_beamformee;
-+      bool he_su_beamformer;
-+      bool he_su_beamformee;
-+      bool he_mu_beamformer;
-+      bool he_full_ul_mumimo;
- };
- /**
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -1280,6 +1280,21 @@ static int ieee80211_start_ap(struct wip
-                       changed |= BSS_CHANGED_HE_BSS_COLOR;
-       }
-+      if (params->he_cap) {
-+              link_conf->he_su_beamformer =
-+                      params->he_cap->phy_cap_info[3] &
-+                              IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
-+              link_conf->he_su_beamformee =
-+                      params->he_cap->phy_cap_info[4] &
-+                              IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE;
-+              link_conf->he_mu_beamformer =
-+                      params->he_cap->phy_cap_info[4] &
-+                              IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
-+              link_conf->he_full_ul_mumimo =
-+                      params->he_cap->phy_cap_info[2] &
-+                              IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO;
-+      }
-+
-       if (sdata->vif.type == NL80211_IFTYPE_AP &&
-           params->mbssid_config.tx_wdev) {
-               err = ieee80211_set_ap_mbssid_options(sdata,