aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/virt_wifi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/virt_wifi.c')
-rw-r--r--drivers/net/wireless/virt_wifi.c54
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;
553unregister_netdev: 554unregister_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
595static 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
600static 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
627static 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. */
594static int __init virt_wifi_init_module(void) 632static 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
654destroy_wiphy:
655 virt_wifi_destroy_wiphy(common_wiphy);
656notifier:
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
620module_init(virt_wifi_init_module); 670module_init(virt_wifi_init_module);