diff options
author | Alexander Aring <alex.aring@gmail.com> | 2014-10-26 09:37:09 +0100 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-10-26 17:24:04 +0100 |
commit | 6001d5223dd458e4f0063df2a24762eb2a619b17 (patch) | |
tree | 0a5f40246fa30dc7b87eec2b78baa59b1c229dc8 | |
parent | ed0a5dce0c29f30ee53a87793206156cf38ae70d (diff) |
mac802154: tx: don't allow if down while sync tx
This patch holds rtnl lock while sync xmit inside of workqueue.
Otherwise we could down the interface while worker xmit handling.
Signed-off-by: Alexander Aring <alex.aring@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r-- | net/mac802154/tx.c | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c index 1a4f6d91ab8c..44390419af86 100644 --- a/net/mac802154/tx.c +++ b/net/mac802154/tx.c @@ -21,6 +21,7 @@ #include <linux/if_arp.h> #include <linux/crc-ccitt.h> +#include <net/rtnetlink.h> #include <net/ieee802154_netdev.h> #include <net/mac802154.h> #include <net/cfg802154.h> @@ -50,16 +51,28 @@ static void mac802154_xmit_worker(struct work_struct *work) struct sk_buff *skb = cb->skb; int res; + rtnl_lock(); + + /* check if ifdown occurred while schedule */ + if (!netif_running(skb->dev)) + goto err_tx; + res = local->ops->xmit_sync(&local->hw, skb); - if (res) { - pr_debug("transmission failed\n"); - /* Restart the netif queue on each sub_if_data object. */ - ieee802154_wake_queue(&local->hw); - kfree_skb(skb); - } else { - /* Restart the netif queue on each sub_if_data object. */ - ieee802154_xmit_complete(&local->hw, skb); - } + if (res) + goto err_tx; + + ieee802154_xmit_complete(&local->hw, skb); + + rtnl_unlock(); + + return; + +err_tx: + /* Restart the netif queue on each sub_if_data object. */ + ieee802154_wake_queue(&local->hw); + rtnl_unlock(); + kfree_skb(skb); + pr_debug("transmission failed\n"); } static netdev_tx_t |