void ssh_interceptor_iface_uninit(SshInterceptor interceptor) { /* Clear interface table and release net_device references. */ ssh_interceptor_clear_ifaces(interceptor); if (interceptor->nf->iface_notifiers_installed == FALSE) return; SSH_ASSERT(in_softirq()); local_bh_enable(); SSH_ASSERT(!in_softirq()); /* Unregister notifier callback */ unregister_netdevice_notifier(&interceptor->nf->notifier_netdev); unregister_inetaddr_notifier(&interceptor->nf->notifier_inetaddr); #ifdef SSH_LINUX_INTERCEPTOR_IPV6 unregister_inet6addr_notifier(&interceptor->nf->notifier_inet6addr); #endif /* SSH_LINUX_INTERCEPTOR_IPV6 */ local_bh_disable(); /* Due to lack of proper locking in linux kernel notifier code, the unregister_*_notifier functions might leave the notifier blocks out of sync, resulting in that the kernel may call an unregistered notifier function. Sleep for a while to decrease the possibility of the bug causing trouble (crash during module unloading). */ mdelay(500); interceptor->nf->iface_notifiers_installed = FALSE; }
void brcmf_detach(struct device *dev) { s32 i; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_pub *drvr = bus_if->drvr; brcmf_dbg(TRACE, "Enter\n"); if (drvr == NULL) return; #ifdef CONFIG_INET unregister_inetaddr_notifier(&drvr->inetaddr_notifier); #endif #if IS_ENABLED(CONFIG_IPV6) unregister_inet6addr_notifier(&drvr->inet6addr_notifier); #endif /* stop firmware event handling */ brcmf_fweh_detach(drvr); if (drvr->config) brcmf_p2p_detach(&drvr->config->p2p); brcmf_bus_change_state(bus_if, BRCMF_BUS_DOWN); /* make sure primary interface removed last */ for (i = BRCMF_MAX_IFS-1; i > -1; i--) brcmf_remove_interface(drvr->iflist[i], false); brcmf_cfg80211_detach(drvr->config); brcmf_fws_deinit(drvr); brcmf_bus_detach(drvr); brcmf_proto_detach(drvr); brcmf_debug_detach(drvr); bus_if->drvr = NULL; kfree(drvr); }