summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--drivers/w1/w1_int.c4
-rw-r--r--include/linux/net.h3
-rw-r--r--include/linux/netlink.h2
-rw-r--r--kernel/audit.c3
-rw-r--r--lib/kobject_uevent.c3
-rw-r--r--net/bridge/netfilter/ebt_ulog.c2
-rw-r--r--net/core/rtnetlink.c2
-rw-r--r--net/decnet/netfilter/dn_rtmsg.c4
-rw-r--r--net/ipv4/fib_frontend.c2
-rw-r--r--net/ipv4/netfilter/ip_queue.c3
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c3
-rw-r--r--net/ipv4/tcp_diag.c3
-rw-r--r--net/ipv6/netfilter/ip6_queue.c2
-rw-r--r--net/netfilter/nfnetlink.c5
-rw-r--r--net/netlink/af_netlink.c108
-rw-r--r--net/xfrm/xfrm_user.c4
-rw-r--r--security/selinux/netlink.c2
17 files changed, 119 insertions, 36 deletions
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index b5a5e04b6d37..8809788dac26 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -88,7 +88,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
 
 	dev->groups = 23;
 	dev->seq = 1;
-	dev->nls = netlink_kernel_create(NETLINK_W1, NULL);
+	dev->nls = netlink_kernel_create(NETLINK_W1, NULL, THIS_MODULE);
 	if (!dev->nls) {
 		printk(KERN_ERR "Failed to create new netlink socket(%u) for w1 master %s.\n",
 			NETLINK_NFLOG, dev->dev.bus_id);
@@ -225,3 +225,5 @@ void w1_remove_master_device(struct w1_bus_master *bm)
 
 EXPORT_SYMBOL(w1_add_master_device);
 EXPORT_SYMBOL(w1_remove_master_device);
+
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_W1);
diff --git a/include/linux/net.h b/include/linux/net.h
index 20cb226b2268..39906619b9d7 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -282,5 +282,8 @@ static struct proto_ops name##_ops = {			\
 #define MODULE_ALIAS_NETPROTO(proto) \
 	MODULE_ALIAS("net-pf-" __stringify(proto))
 
+#define MODULE_ALIAS_NET_PF_PROTO(pf, proto) \
+	MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto))
+
 #endif /* __KERNEL__ */
 #endif	/* _LINUX_NET_H */
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 6552b71bfa73..1c50fea8995b 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -117,7 +117,7 @@ struct netlink_skb_parms
 #define NETLINK_CREDS(skb)	(&NETLINK_CB((skb)).creds)
 
 
-extern struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));
+extern struct sock *netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct module *module);
 extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
 extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
 extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 pid,
diff --git a/kernel/audit.c b/kernel/audit.c
index ef35166fdc29..ed4019563d56 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -514,7 +514,8 @@ static int __init audit_init(void)
 {
 	printk(KERN_INFO "audit: initializing netlink socket (%s)\n",
 	       audit_default ? "enabled" : "disabled");
-	audit_sock = netlink_kernel_create(NETLINK_AUDIT, audit_receive);
+	audit_sock = netlink_kernel_create(NETLINK_AUDIT, audit_receive,
+					   THIS_MODULE);
 	if (!audit_sock)
 		audit_panic("cannot initialize netlink socket");
 
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 8e49d21057e4..88f4d746aa05 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -153,7 +153,8 @@ EXPORT_SYMBOL_GPL(kobject_uevent_atomic);
 
 static int __init kobject_uevent_init(void)
 {
-	uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, NULL);
+	uevent_sock = netlink_kernel_create(NETLINK_KOBJECT_UEVENT, NULL,
+					    THIS_MODULE);
 
 	if (!uevent_sock) {
 		printk(KERN_ERR
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
index 01af4fcef26d..561d75c8ed5a 100644
--- a/net/bridge/netfilter/ebt_ulog.c
+++ b/net/bridge/netfilter/ebt_ulog.c
@@ -258,7 +258,7 @@ static int __init init(void)
 		spin_lock_init(&ulog_buffers[i].lock);
 	}
 
-	ebtulognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
+	ebtulognl = netlink_kernel_create(NETLINK_NFLOG, NULL, THIS_MODULE);
 	if (!ebtulognl)
 		ret = -ENOMEM;
 	else if ((ret = ebt_register_watcher(&ulog)))
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 4b1bb30e6381..9b3c61f1a37d 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -708,7 +708,7 @@ void __init rtnetlink_init(void)
 	if (!rta_buf)
 		panic("rtnetlink_init: cannot allocate rta_buf\n");
 
-	rtnl = netlink_kernel_create(NETLINK_ROUTE, rtnetlink_rcv);
+	rtnl = netlink_kernel_create(NETLINK_ROUTE, rtnetlink_rcv, THIS_MODULE);
 	if (rtnl == NULL)
 		panic("rtnetlink_init: cannot initialize rtnetlink\n");
 	netlink_set_nonroot(NETLINK_ROUTE, NL_NONROOT_RECV);
diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
index 284a9998e53d..3068fddb2da3 100644
--- a/net/decnet/netfilter/dn_rtmsg.c
+++ b/net/decnet/netfilter/dn_rtmsg.c
@@ -138,7 +138,8 @@ static int __init init(void)
 {
 	int rv = 0;
 
-	dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, dnrmg_receive_user_sk);
+	dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, dnrmg_receive_user_sk,
+				      THIS_MODULE);
 	if (dnrmg == NULL) {
 		printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket");
 		return -ENOMEM;
@@ -162,6 +163,7 @@ static void __exit fini(void)
 MODULE_DESCRIPTION("DECnet Routing Message Grabulator");
 MODULE_AUTHOR("Steven Whitehouse <steve@chygwyn.com>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_DNRTMSG);
 
 module_init(init);
 module_exit(fini);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index e5722084239b..b5e2f1550c91 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -567,7 +567,7 @@ static void nl_fib_input(struct sock *sk, int len)
 
 static void nl_fib_lookup_init(void)
 {
-      netlink_kernel_create(NETLINK_FIB_LOOKUP, nl_fib_input);
+      netlink_kernel_create(NETLINK_FIB_LOOKUP, nl_fib_input, THIS_MODULE);
 }
 
 static void fib_disable_ip(struct net_device *dev, int force)
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index ae975ac59c6a..b237f7fcad92 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -692,7 +692,8 @@ init_or_cleanup(int init)
 		goto cleanup;
 
 	netlink_register_notifier(&ipq_nl_notifier);
-	ipqnl = netlink_kernel_create(NETLINK_FIREWALL, ipq_rcv_sk);
+	ipqnl = netlink_kernel_create(NETLINK_FIREWALL, ipq_rcv_sk,
+				      THIS_MODULE);
 	if (ipqnl == NULL) {
 		printk(KERN_ERR "ip_queue: failed to create netlink socket\n");
 		goto cleanup_netlink_notifier;
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index 52a0076302a7..4ea8371ab270 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -62,6 +62,7 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 MODULE_DESCRIPTION("iptables userspace logging module");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NFLOG);
 
 #define ULOG_NL_EVENT		111		/* Harald's favorite number */
 #define ULOG_MAXNLGROUPS	32		/* numer of nlgroups */
@@ -372,7 +373,7 @@ static int __init init(void)
 		ulog_buffers[i].timer.data = i;
 	}
 
-	nflognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
+	nflognl = netlink_kernel_create(NETLINK_NFLOG, NULL, THIS_MODULE);
 	if (!nflognl)
 		return -ENOMEM;
 
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index f66945cb158f..f79bd11a4701 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -774,7 +774,8 @@ static void tcpdiag_rcv(struct sock *sk, int len)
 
 static int __init tcpdiag_init(void)
 {
-	tcpnl = netlink_kernel_create(NETLINK_TCPDIAG, tcpdiag_rcv);
+	tcpnl = netlink_kernel_create(NETLINK_TCPDIAG, tcpdiag_rcv,
+				      THIS_MODULE);
 	if (tcpnl == NULL)
 		return -ENOMEM;
 	return 0;
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 7130603a32c5..1c3d247a22cc 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -685,7 +685,7 @@ init_or_cleanup(int init)
 		goto cleanup;
 
 	netlink_register_notifier(&ipq_nl_notifier);
-	ipqnl = netlink_kernel_create(NETLINK_IP6_FW, ipq_rcv_sk);
+	ipqnl = netlink_kernel_create(NETLINK_IP6_FW, ipq_rcv_sk, THIS_MODULE);
 	if (ipqnl == NULL) {
 		printk(KERN_ERR "ip6_queue: failed to create netlink socket\n");
 		goto cleanup_netlink_notifier;
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index b0ed57981847..6210ca42166c 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -38,6 +38,8 @@
 #include <linux/netfilter/nfnetlink.h>
 
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
 
 static char __initdata nfversion[] = "0.30";
 
@@ -324,7 +326,8 @@ int __init nfnetlink_init(void)
 {
 	printk("Netfilter messages via NETLINK v%s.\n", nfversion);
 
-	nfnl = netlink_kernel_create(NETLINK_NETFILTER, nfnetlink_rcv);
+	nfnl = netlink_kernel_create(NETLINK_NETFILTER, nfnetlink_rcv,
+				     THIS_MODULE);
 	if (!nfnl) {
 		printk(KERN_ERR "cannot initialize nfnetlink!\n");
 		return -1;
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index ff774a06c89d..5d487cd69c8c 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -13,7 +13,12 @@
  *                               added netlink_proto_exit
  * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo <acme@conectiva.com.br>
  * 				 use nlk_sk, as sk->protinfo is on a diet 8)
- *
+ * Fri Jul 22 19:51:12 MEST 2005 Harald Welte <laforge@gnumonks.org>
+ * 				 - inc module use count of module that owns
+ * 				   the kernel socket in case userspace opens
+ * 				   socket of same protocol
+ * 				 - remove all module support, since netlink is
+ * 				   mandatory if CONFIG_NET=y these days
  */
 
 #include <linux/config.h>
@@ -92,6 +97,7 @@ struct netlink_table {
 	struct nl_pid_hash hash;
 	struct hlist_head mc_list;
 	unsigned int nl_nonroot;
+	struct proto_ops *p_ops;
 };
 
 static struct netlink_table *nl_table;
@@ -341,7 +347,21 @@ static int netlink_create(struct socket *sock, int protocol)
 	if (protocol<0 || protocol >= MAX_LINKS)
 		return -EPROTONOSUPPORT;
 
-	sock->ops = &netlink_ops;
+	netlink_table_grab();
+	if (!nl_table[protocol].hash.entries) {
+#ifdef CONFIG_KMOD
+		/* We do 'best effort'.  If we find a matching module,
+		 * it is loaded.  If not, we don't return an error to
+		 * allow pure userspace<->userspace communication. -HW
+		 */
+		netlink_table_ungrab();
+		request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol);
+		netlink_table_grab();
+#endif
+	}
+	netlink_table_ungrab();
+
+	sock->ops = nl_table[protocol].p_ops;
 
 	sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1);
 	if (!sk)
@@ -394,6 +414,22 @@ static int netlink_release(struct socket *sock)
 					  };
 		notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n);
 	}	
+
+	/* When this is a kernel socket, we need to remove the owner pointer,
+	 * since we don't know whether the module will be dying at any given
+	 * point - HW
+	 */
+	if (!nlk->pid) {
+		struct proto_ops *p_tmp;
+
+		netlink_table_grab();
+		p_tmp = nl_table[sk->sk_protocol].p_ops;
+		if (p_tmp != &netlink_ops) {
+			nl_table[sk->sk_protocol].p_ops = &netlink_ops;
+			kfree(p_tmp);
+		}
+		netlink_table_ungrab();
+	}
 	
 	sock_put(sk);
 	return 0;
@@ -1023,8 +1059,9 @@ static void netlink_data_ready(struct sock *sk, int len)
  */
 
 struct sock *
-netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len))
+netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct module *module)
 {
+	struct proto_ops *p_ops;
 	struct socket *sock;
 	struct sock *sk;
 
@@ -1034,22 +1071,63 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len))
 	if (unit<0 || unit>=MAX_LINKS)
 		return NULL;
 
+	/* Do a quick check, to make us not go down to netlink_insert()
+	 * if protocol already has kernel socket.
+	 */
+	sk = netlink_lookup(unit, 0);
+	if (unlikely(sk)) {
+		sock_put(sk);
+		return NULL;
+	}
+
 	if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock))
 		return NULL;
 
+	sk = NULL;
+	if (module) {
+		/* Every registering protocol implemented in a module needs
+		 * it's own p_ops, since the socket code cannot deal with
+		 * module refcounting otherwise.  -HW
+		 */
+		p_ops = kmalloc(sizeof(*p_ops), GFP_KERNEL);
+		if (!p_ops)
+			goto out_sock_release;
+
+		memcpy(p_ops, &netlink_ops, sizeof(*p_ops));
+		p_ops->owner = module;
+	} else
+		p_ops = &netlink_ops;
+
+	netlink_table_grab();
+	nl_table[unit].p_ops = p_ops;
+	netlink_table_ungrab();
+
 	if (netlink_create(sock, unit) < 0) {
-		sock_release(sock);
-		return NULL;
+		sk = NULL;
+		goto out_kfree_p_ops;
 	}
+
 	sk = sock->sk;
 	sk->sk_data_ready = netlink_data_ready;
 	if (input)
 		nlk_sk(sk)->data_ready = input;
 
 	if (netlink_insert(sk, 0)) {
-		sock_release(sock);
-		return NULL;
+		sk = NULL;
+		goto out_kfree_p_ops;
+	}
+
+	return sk;
+
+out_kfree_p_ops:
+	netlink_table_grab();
+	if (nl_table[unit].p_ops != &netlink_ops) {
+		kfree(nl_table[unit].p_ops);
+		nl_table[unit].p_ops = &netlink_ops;
 	}
+	netlink_table_ungrab();
+out_sock_release:
+	sock_release(sock);
 	return sk;
 }
 
@@ -1413,6 +1491,8 @@ enomem:
 	for (i = 0; i < MAX_LINKS; i++) {
 		struct nl_pid_hash *hash = &nl_table[i].hash;
 
+		nl_table[i].p_ops = &netlink_ops;
+
 		hash->table = nl_pid_hash_alloc(1 * sizeof(*hash->table));
 		if (!hash->table) {
 			while (i-- > 0)
@@ -1438,21 +1518,7 @@ out:
 	return err;
 }
 
-static void __exit netlink_proto_exit(void)
-{
-	sock_unregister(PF_NETLINK);
-	proc_net_remove("netlink");
-	kfree(nl_table);
-	nl_table = NULL;
-	proto_unregister(&netlink_proto);
-}
-
 core_initcall(netlink_proto_init);
-module_exit(netlink_proto_exit);
-
-MODULE_LICENSE("GPL");
-
-MODULE_ALIAS_NETPROTO(PF_NETLINK);
 
 EXPORT_SYMBOL(netlink_ack);
 EXPORT_SYMBOL(netlink_broadcast);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 8da3e25b2c4c..33ceeea783b1 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1519,7 +1519,8 @@ static int __init xfrm_user_init(void)
 {
 	printk(KERN_INFO "Initializing IPsec netlink socket\n");
 
-	xfrm_nl = netlink_kernel_create(NETLINK_XFRM, xfrm_netlink_rcv);
+	xfrm_nl = netlink_kernel_create(NETLINK_XFRM, xfrm_netlink_rcv,
+					THIS_MODULE);
 	if (xfrm_nl == NULL)
 		return -ENOMEM;
 
@@ -1537,3 +1538,4 @@ static void __exit xfrm_user_exit(void)
 module_init(xfrm_user_init);
 module_exit(xfrm_user_exit);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);
diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c
index 18d08acafa78..341dbe2579be 100644
--- a/security/selinux/netlink.c
+++ b/security/selinux/netlink.c
@@ -103,7 +103,7 @@ void selnl_notify_policyload(u32 seqno)
 
 static int __init selnl_init(void)
 {
-	selnl = netlink_kernel_create(NETLINK_SELINUX, NULL);
+	selnl = netlink_kernel_create(NETLINK_SELINUX, NULL, THIS_MODULE);
 	if (selnl == NULL)
 		panic("SELinux:  Cannot create netlink socket.");
 	netlink_set_nonroot(NETLINK_SELINUX, NL_NONROOT_RECV);