summaryrefslogtreecommitdiffstats
path: root/net/mac802154
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2017-05-08 12:52:56 -0400
committerDavid S. Miller <davem@davemloft.net>2017-06-07 15:53:24 -0400
commitcf124db566e6b036b8bcbe8decbed740bdfac8c6 (patch)
treeebe7dd29c461575ec091583da4ec5dd75ffcd5d2 /net/mac802154
parent7005cade1bdbb423413f8aafcbf17a1ec614a585 (diff)
net: Fix inconsistent teardown and release of private netdev state.
Network devices can allocate reasources and private memory using netdev_ops->ndo_init(). However, the release of these resources can occur in one of two different places. Either netdev_ops->ndo_uninit() or netdev->destructor(). The decision of which operation frees the resources depends upon whether it is necessary for all netdev refs to be released before it is safe to perform the freeing. netdev_ops->ndo_uninit() presumably can occur right after the NETDEV_UNREGISTER notifier completes and the unicast and multicast address lists are flushed. netdev->destructor(), on the other hand, does not run until the netdev references all go away. Further complicating the situation is that netdev->destructor() almost universally does also a free_netdev(). This creates a problem for the logic in register_netdevice(). Because all callers of register_netdevice() manage the freeing of the netdev, and invoke free_netdev(dev) if register_netdevice() fails. If netdev_ops->ndo_init() succeeds, but something else fails inside of register_netdevice(), it does call ndo_ops->ndo_uninit(). But it is not able to invoke netdev->destructor(). This is because netdev->destructor() will do a free_netdev() and then the caller of register_netdevice() will do the same. However, this means that the resources that would normally be released by netdev->destructor() will not be. Over the years drivers have added local hacks to deal with this, by invoking their destructor parts by hand when register_netdevice() fails. Many drivers do not try to deal with this, and instead we have leaks. Let's close this hole by formalizing the distinction between what private things need to be freed up by netdev->destructor() and whether the driver needs unregister_netdevice() to perform the free_netdev(). netdev->priv_destructor() performs all actions to free up the private resources that used to be freed by netdev->destructor(), except for free_netdev(). netdev->needs_free_netdev is a boolean that indicates whether free_netdev() should be done at the end of unregister_netdevice(). Now, register_netdevice() can sanely release all resources after ndo_ops->ndo_init() succeeds, by invoking both ndo_ops->ndo_uninit() and netdev->priv_destructor(). And at the end of unregister_netdevice(), we invoke netdev->priv_destructor() and optionally call free_netdev(). Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac802154')
-rw-r--r--net/mac802154/iface.c7
1 files changed, 3 insertions, 4 deletions
diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c
index 06019dba4b10..bd88a9b80773 100644
--- a/net/mac802154/iface.c
+++ b/net/mac802154/iface.c
@@ -526,8 +526,6 @@ static void mac802154_wpan_free(struct net_device *dev)
526 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 526 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
527 527
528 mac802154_llsec_destroy(&sdata->sec); 528 mac802154_llsec_destroy(&sdata->sec);
529
530 free_netdev(dev);
531} 529}
532 530
533static void ieee802154_if_setup(struct net_device *dev) 531static void ieee802154_if_setup(struct net_device *dev)
@@ -593,7 +591,8 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
593 sdata->dev->dev_addr); 591 sdata->dev->dev_addr);
594 592
595 sdata->dev->header_ops = &mac802154_header_ops; 593 sdata->dev->header_ops = &mac802154_header_ops;
596 sdata->dev->destructor = mac802154_wpan_free; 594 sdata->dev->needs_free_netdev = true;
595 sdata->dev->priv_destructor = mac802154_wpan_free;
597 sdata->dev->netdev_ops = &mac802154_wpan_ops; 596 sdata->dev->netdev_ops = &mac802154_wpan_ops;
598 sdata->dev->ml_priv = &mac802154_mlme_wpan; 597 sdata->dev->ml_priv = &mac802154_mlme_wpan;
599 wpan_dev->promiscuous_mode = false; 598 wpan_dev->promiscuous_mode = false;
@@ -608,7 +607,7 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata,
608 607
609 break; 608 break;
610 case NL802154_IFTYPE_MONITOR: 609 case NL802154_IFTYPE_MONITOR:
611 sdata->dev->destructor = free_netdev; 610 sdata->dev->needs_free_netdev = true;
612 sdata->dev->netdev_ops = &mac802154_monitor_ops; 611 sdata->dev->netdev_ops = &mac802154_monitor_ops;
613 wpan_dev->promiscuous_mode = true; 612 wpan_dev->promiscuous_mode = true;
614 break; 613 break;