net: mac802154: Add a warning in the hot path
authorMiquel Raynal <miquel.raynal@bootlin.com>
Thu, 19 May 2022 15:05:15 +0000 (17:05 +0200)
committerStefan Schmidt <stefan@datenfreihafen.org>
Fri, 10 Jun 2022 07:48:41 +0000 (09:48 +0200)
We should never start a transmission after the queue has been stopped.

But because it might work we don't kill the function here but rather
warn loudly the user that something is wrong.

Set a flag when the queue should remain stopped. Reset this flag when
the queue actually gets restarded. Just check this value to know if a
transmission is legitimate, warn if it is not.

Turn the flags variable into an unsigned long to allow the use of atomic
helpers on it.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Alexander Aring <aahringo@redhat.com>
Link: https://lore.kernel.org/r/20220519150516.443078-11-miquel.raynal@bootlin.com
Signed-off-by: Stefan Schmidt <stefan@datenfreihafen.org>
include/net/cfg802154.h
net/mac802154/tx.c
net/mac802154/util.c

index 0804d79669a433c6aefab8dd89eeaef5ec9690eb..428cece2220594a89403b937a0f3825b119de251 100644 (file)
@@ -166,11 +166,14 @@ wpan_phy_cca_cmp(const struct wpan_phy_cca *a, const struct wpan_phy_cca *b)
  *     level setting.
  * @WPAN_PHY_FLAG_CCA_MODE: Indicates that transceiver will support cca mode
  *     setting.
+ * @WPAN_PHY_FLAG_STATE_QUEUE_STOPPED: Indicates that the transmit queue was
+ *     temporarily stopped.
  */
 enum wpan_phy_flags {
        WPAN_PHY_FLAG_TXPOWER           = BIT(1),
        WPAN_PHY_FLAG_CCA_ED_LEVEL      = BIT(2),
        WPAN_PHY_FLAG_CCA_MODE          = BIT(3),
+       WPAN_PHY_FLAG_STATE_QUEUE_STOPPED = BIT(4),
 };
 
 struct wpan_phy {
@@ -182,7 +185,7 @@ struct wpan_phy {
         */
        const void *privid;
 
-       u32 flags;
+       unsigned long flags;
 
        /*
         * This is a PIB according to 802.15.4-2011.
index 4827391600f6a0e9f2ba15cf8a5340c6f8ad5fc7..6188f42276e781f7d837d0ce739f227ba7320798 100644 (file)
@@ -123,9 +123,13 @@ static int ieee802154_sync_queue(struct ieee802154_local *local)
 
 int ieee802154_sync_and_hold_queue(struct ieee802154_local *local)
 {
+       int ret;
+
        ieee802154_hold_queue(local);
+       ret = ieee802154_sync_queue(local);
+       set_bit(WPAN_PHY_FLAG_STATE_QUEUE_STOPPED, &local->phy->flags);
 
-       return ieee802154_sync_queue(local);
+       return ret;
 }
 
 int ieee802154_mlme_op_pre(struct ieee802154_local *local)
@@ -172,9 +176,19 @@ int ieee802154_mlme_tx_one(struct ieee802154_local *local, struct sk_buff *skb)
        return ret;
 }
 
+static bool ieee802154_queue_is_stopped(struct ieee802154_local *local)
+{
+       return test_bit(WPAN_PHY_FLAG_STATE_QUEUE_STOPPED, &local->phy->flags);
+}
+
 static netdev_tx_t
 ieee802154_hot_tx(struct ieee802154_local *local, struct sk_buff *skb)
 {
+       /* Warn if the net interface tries to transmit frames while the
+        * ieee802154 core assumes the queue is stopped.
+        */
+       WARN_ON_ONCE(ieee802154_queue_is_stopped(local));
+
        return ieee802154_tx(local, skb);
 }
 
index 5e1fcc7b0123bd1e751a7f67dead26c5137f517a..60eb7bd3bfc14b4c6d606b7427318c51e290efd8 100644 (file)
@@ -29,6 +29,7 @@ static void ieee802154_wake_queue(struct ieee802154_hw *hw)
        struct ieee802154_sub_if_data *sdata;
 
        rcu_read_lock();
+       clear_bit(WPAN_PHY_FLAG_STATE_QUEUE_STOPPED, &local->phy->flags);
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                if (!sdata->dev)
                        continue;