@@ -548,6 +548,7 @@ static int virt_wifi_newlink(struct net *src_net, struct net_device *dev,
548
548
priv -> is_connected = false;
549
549
priv -> is_up = false;
550
550
INIT_DELAYED_WORK (& priv -> connect , virt_wifi_connect_complete );
551
+ __module_get (THIS_MODULE );
551
552
552
553
return 0 ;
553
554
unregister_netdev :
@@ -578,6 +579,7 @@ static void virt_wifi_dellink(struct net_device *dev,
578
579
netdev_upper_dev_unlink (priv -> lowerdev , dev );
579
580
580
581
unregister_netdevice_queue (dev , head );
582
+ module_put (THIS_MODULE );
581
583
582
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
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
631
/* Acquires and releases the rtnl lock. */
594
632
static int __init virt_wifi_init_module (void )
595
633
{
@@ -598,14 +636,25 @@ static int __init virt_wifi_init_module(void)
598
636
/* Guaranteed to be locallly-administered and not multicast. */
599
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
644
common_wiphy = virt_wifi_make_wiphy ();
602
645
if (!common_wiphy )
603
- return - ENOMEM ;
646
+ goto notifier ;
604
647
605
648
err = rtnl_link_register (& virt_wifi_link_ops );
606
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
658
return err ;
610
659
}
611
660
@@ -615,6 +664,7 @@ static void __exit virt_wifi_cleanup_module(void)
615
664
/* Will delete any devices that depend on the wiphy. */
616
665
rtnl_link_unregister (& virt_wifi_link_ops );
617
666
virt_wifi_destroy_wiphy (common_wiphy );
667
+ unregister_netdevice_notifier (& virt_wifi_notifier );
618
668
}
619
669
620
670
module_init (virt_wifi_init_module );
0 commit comments