wifi: mac80211: netdev compatible TX stop for iTXQ drivers
authorAlexander Wetzel <alexander@wetzel-home.de>
Tue, 20 Sep 2022 15:55:41 +0000 (17:55 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 7 Oct 2022 12:48:14 +0000 (14:48 +0200)
Properly handle TX stop for internal queues (iTXQs) within mac80211.

mac80211 must not stop netdev queues when using mac80211 iTXQs.
For these drivers the netdev interface is created with IFF_NO_QUEUE.

While netdev still drops frames for IFF_NO_QUEUE interfaces when we stop
the netdev queues, it also prints a warning when this happens:
Assuming the mac80211 interface is called wlan0 we would get
"Virtual device wlan0 asks to queue packet!" when netdev has to drop a
frame.

This patch is keeping the harmless netdev queue starts for iTXQ drivers.

Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/iface.c
net/mac80211/tx.c

index b15afa77b87c076c14d1114ea39fb6749c8f3493..dd9ac1f7d2ea6771ac4328a36e1dece4c29b30b4 100644 (file)
@@ -461,7 +461,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
        /*
         * Stop TX on this interface first.
         */
-       if (sdata->dev)
+       if (!local->ops->wake_tx_queue && sdata->dev)
                netif_tx_stop_all_queues(sdata->dev);
 
        ieee80211_roc_purge(local, sdata);
@@ -1412,8 +1412,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                        sdata->vif.type != NL80211_IFTYPE_STATION);
        }
 
-       set_bit(SDATA_STATE_RUNNING, &sdata->state);
-
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_P2P_DEVICE:
                rcu_assign_pointer(local->p2p_sdata, sdata);
@@ -1472,6 +1470,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
                spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
        }
 
+       set_bit(SDATA_STATE_RUNNING, &sdata->state);
+
        return 0;
  err_del_interface:
        drv_remove_interface(local, sdata);
index 27c964be102e16c9cc7e74b4cd2c0983886b9122..a364148149f9413b632e6639ec1d66f32da8aa54 100644 (file)
@@ -2319,6 +2319,10 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
        u16 len_rthdr;
        int hdrlen;
 
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (unlikely(!ieee80211_sdata_running(sdata)))
+               goto fail;
+
        memset(info, 0, sizeof(*info));
        info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
                      IEEE80211_TX_CTL_INJECTED;
@@ -2378,8 +2382,6 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
         * This is necessary, for example, for old hostapd versions that
         * don't use nl80211-based management TX/RX.
         */
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
        list_for_each_entry_rcu(tmp_sdata, &local->interfaces, list) {
                if (!ieee80211_sdata_running(tmp_sdata))
                        continue;
@@ -4169,7 +4171,7 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
        struct sk_buff *next;
        int len = skb->len;
 
-       if (unlikely(skb->len < ETH_HLEN)) {
+       if (unlikely(!ieee80211_sdata_running(sdata) || skb->len < ETH_HLEN)) {
                kfree_skb(skb);
                return;
        }
@@ -4566,7 +4568,7 @@ netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb,
        struct ieee80211_key *key;
        struct sta_info *sta;
 
-       if (unlikely(skb->len < ETH_HLEN)) {
+       if (unlikely(!ieee80211_sdata_running(sdata) || skb->len < ETH_HLEN)) {
                kfree_skb(skb);
                return NETDEV_TX_OK;
        }