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; }
/* Interceptor initialization. Called by init_module(). */ int ssh_interceptor_init(void) { int ret; /* Print version info for log files */ printk(KERN_INFO "VPNClient built on " __DATE__ " " __TIME__ "\n"); ret = ssh_interceptor_init_kernel_services(); if (ret != 0) { goto error0; } SSH_ASSERT(ssh_interceptor_context != NULL); ret = ssh_interceptor_hook_magic_init(); if (ret != 0) { goto error1; } ret = ssh_interceptor_init_engine(ssh_interceptor_context); if (ret != 0) { goto error4; } ret = ssh_interceptor_init_external_interfaces(ssh_interceptor_context); if (ret != 0) { goto error5; } return 0; error5: local_bh_disable(); ssh_interceptor_uninit_engine(ssh_interceptor_context); local_bh_enable(); error4: ssh_interceptor_clear_ifaces(ssh_interceptor_context); error1: local_bh_disable(); ssh_interceptor_uninit_kernel_services(); local_bh_enable(); error0: return ret; }