diff options
Diffstat (limited to 'drivers/net/wireless/virt_wifi.c')
-rw-r--r-- | drivers/net/wireless/virt_wifi.c | 54 |
1 files changed, 52 insertions, 2 deletions
diff --git a/drivers/net/wireless/virt_wifi.c b/drivers/net/wireless/virt_wifi.c index be92e1220284..7997cc6de334 100644 --- a/drivers/net/wireless/virt_wifi.c +++ b/drivers/net/wireless/virt_wifi.c | |||
@@ -548,6 +548,7 @@ static int virt_wifi_newlink(struct net *src_net, struct net_device *dev, | |||
548 | priv->is_connected = false; | 548 | priv->is_connected = false; |
549 | priv->is_up = false; | 549 | priv->is_up = false; |
550 | INIT_DELAYED_WORK(&priv->connect, virt_wifi_connect_complete); | 550 | INIT_DELAYED_WORK(&priv->connect, virt_wifi_connect_complete); |
551 | __module_get(THIS_MODULE); | ||
551 | 552 | ||
552 | return 0; | 553 | return 0; |
553 | unregister_netdev: | 554 | unregister_netdev: |
@@ -578,6 +579,7 @@ static void virt_wifi_dellink(struct net_device *dev, | |||
578 | netdev_upper_dev_unlink(priv->lowerdev, dev); | 579 | netdev_upper_dev_unlink(priv->lowerdev, dev); |
579 | 580 | ||
580 | unregister_netdevice_queue(dev, head); | 581 | unregister_netdevice_queue(dev, head); |
582 | module_put(THIS_MODULE); | ||
581 | 583 | ||
582 | /* Deleting the wiphy is handled in the module destructor. */ | 584 | /* Deleting the wiphy is handled in the module destructor. */ |
583 | } | 585 | } |
@@ -590,6 +592,42 @@ static struct rtnl_link_ops virt_wifi_link_ops = { | |||
590 | .priv_size = sizeof(struct virt_wifi_netdev_priv), | 592 | .priv_size = sizeof(struct virt_wifi_netdev_priv), |
591 | }; | 593 | }; |
592 | 594 | ||
595 | static bool netif_is_virt_wifi_dev(const struct net_device *dev) | ||
596 | { | ||
597 | return rcu_access_pointer(dev->rx_handler) == virt_wifi_rx_handler; | ||
598 | } | ||
599 | |||
600 | static int virt_wifi_event(struct notifier_block *this, unsigned long event, | ||
601 | void *ptr) | ||
602 | { | ||
603 | struct net_device *lower_dev = netdev_notifier_info_to_dev(ptr); | ||
604 | struct virt_wifi_netdev_priv *priv; | ||
605 | struct net_device *upper_dev; | ||
606 | LIST_HEAD(list_kill); | ||
607 | |||
608 | if (!netif_is_virt_wifi_dev(lower_dev)) | ||
609 | return NOTIFY_DONE; | ||
610 | |||
611 | switch (event) { | ||
612 | case NETDEV_UNREGISTER: | ||
613 | priv = rtnl_dereference(lower_dev->rx_handler_data); | ||
614 | if (!priv) | ||
615 | return NOTIFY_DONE; | ||
616 | |||
617 | upper_dev = priv->upperdev; | ||
618 | |||
619 | upper_dev->rtnl_link_ops->dellink(upper_dev, &list_kill); | ||
620 | unregister_netdevice_many(&list_kill); | ||
621 | break; | ||
622 | } | ||
623 | |||
624 | return NOTIFY_DONE; | ||
625 | } | ||
626 | |||
627 | static struct notifier_block virt_wifi_notifier = { | ||
628 | .notifier_call = virt_wifi_event, | ||
629 | }; | ||
630 | |||
593 | /* Acquires and releases the rtnl lock. */ | 631 | /* Acquires and releases the rtnl lock. */ |
594 | static int __init virt_wifi_init_module(void) | 632 | static int __init virt_wifi_init_module(void) |
595 | { | 633 | { |
@@ -598,14 +636,25 @@ static int __init virt_wifi_init_module(void) | |||
598 | /* Guaranteed to be locallly-administered and not multicast. */ | 636 | /* Guaranteed to be locallly-administered and not multicast. */ |
599 | eth_random_addr(fake_router_bssid); | 637 | eth_random_addr(fake_router_bssid); |
600 | 638 | ||
639 | err = register_netdevice_notifier(&virt_wifi_notifier); | ||
640 | if (err) | ||
641 | return err; | ||
642 | |||
643 | err = -ENOMEM; | ||
601 | common_wiphy = virt_wifi_make_wiphy(); | 644 | common_wiphy = virt_wifi_make_wiphy(); |
602 | if (!common_wiphy) | 645 | if (!common_wiphy) |
603 | return -ENOMEM; | 646 | goto notifier; |
604 | 647 | ||
605 | err = rtnl_link_register(&virt_wifi_link_ops); | 648 | err = rtnl_link_register(&virt_wifi_link_ops); |
606 | if (err) | 649 | if (err) |
607 | virt_wifi_destroy_wiphy(common_wiphy); | 650 | goto destroy_wiphy; |
608 | 651 | ||
652 | return 0; | ||
653 | |||
654 | destroy_wiphy: | ||
655 | virt_wifi_destroy_wiphy(common_wiphy); | ||
656 | notifier: | ||
657 | unregister_netdevice_notifier(&virt_wifi_notifier); | ||
609 | return err; | 658 | return err; |
610 | } | 659 | } |
611 | 660 | ||
@@ -615,6 +664,7 @@ static void __exit virt_wifi_cleanup_module(void) | |||
615 | /* Will delete any devices that depend on the wiphy. */ | 664 | /* Will delete any devices that depend on the wiphy. */ |
616 | rtnl_link_unregister(&virt_wifi_link_ops); | 665 | rtnl_link_unregister(&virt_wifi_link_ops); |
617 | virt_wifi_destroy_wiphy(common_wiphy); | 666 | virt_wifi_destroy_wiphy(common_wiphy); |
667 | unregister_netdevice_notifier(&virt_wifi_notifier); | ||
618 | } | 668 | } |
619 | 669 | ||
620 | module_init(virt_wifi_init_module); | 670 | module_init(virt_wifi_init_module); |