diff mbox

[RFC] netlink: add socket destruction notification

Message ID 1254473048.3959.76.camel@johannes.local
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

Johannes Berg Oct. 2, 2009, 8:44 a.m. UTC
When we want to keep track of resources associated with applications, we
need to know when an app is going away. Add a notification function to
netlink that tells us that, and also hook it up to generic netlink so
generic netlink can notify the families. Due to the way generic netlink
works though, we need to notify all families and they have to sort out
whatever resources some commands associated with the socket themselves.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
---
 drivers/connector/connector.c       |    2 +-
 drivers/scsi/scsi_netlink.c         |    2 +-
 drivers/scsi/scsi_transport_iscsi.c |    2 +-
 include/linux/netlink.h             |    1 +
 include/net/genetlink.h             |    3 +++
 kernel/audit.c                      |    3 ++-
 lib/kobject_uevent.c                |    2 +-
 net/bridge/netfilter/ebt_ulog.c     |    2 +-
 net/core/rtnetlink.c                |    3 ++-
 net/decnet/netfilter/dn_rtmsg.c     |    2 +-
 net/ipv4/fib_frontend.c             |    2 +-
 net/ipv4/inet_diag.c                |    2 +-
 net/ipv4/netfilter/ip_queue.c       |    2 +-
 net/ipv4/netfilter/ipt_ULOG.c       |    6 +++---
 net/ipv6/netfilter/ip6_queue.c      |    2 +-
 net/netfilter/nfnetlink.c           |    2 +-
 net/netlink/af_netlink.c            |    6 ++++++
 net/netlink/genetlink.c             |   18 ++++++++++++++++--
 net/xfrm/xfrm_user.c                |    2 +-
 security/selinux/netlink.c          |    3 ++-
 20 files changed, 47 insertions(+), 20 deletions(-)



--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

David Miller Nov. 6, 2009, 5:08 a.m. UTC | #1
From: Johannes Berg <johannes@sipsolutions.net>
Date: Fri, 02 Oct 2009 10:44:08 +0200

> When we want to keep track of resources associated with applications, we
> need to know when an app is going away. Add a notification function to
> netlink that tells us that, and also hook it up to generic netlink so
> generic netlink can notify the families. Due to the way generic netlink
> works though, we need to notify all families and they have to sort out
> whatever resources some commands associated with the socket themselves.
> 
> Signed-off-by: Johannes Berg <johannes@sipsolutions.net>

No fundamental objections.

However, as a followup, netlink_kernel_create() is becomming
function_that_takes_too_many_arguments().

At this point it's better to just pass two arguments, the network
namespace pointer, and a pointer to a "const struct netlink_kern_info"
that holds the rest of the parameters.

Could you make that change too?

Thanks!
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Johannes Berg Nov. 6, 2009, 8:55 a.m. UTC | #2
On Thu, 2009-11-05 at 21:08 -0800, David Miller wrote:

> > When we want to keep track of resources associated with applications, we
> > need to know when an app is going away. Add a notification function to
> > netlink that tells us that, and also hook it up to generic netlink so
> > generic netlink can notify the families. Due to the way generic netlink
> > works though, we need to notify all families and they have to sort out
> > whatever resources some commands associated with the socket themselves.

> No fundamental objections.

:)

> However, as a followup, netlink_kernel_create() is becomming
> function_that_takes_too_many_arguments().
> 
> At this point it's better to just pass two arguments, the network
> namespace pointer, and a pointer to a "const struct netlink_kern_info"
> that holds the rest of the parameters.
> 
> Could you make that change too?

Yeah, I agree -- will change.

johannes
Patrick McHardy Nov. 6, 2009, 3:21 p.m. UTC | #3
Johannes Berg wrote:
> When we want to keep track of resources associated with applications, we
> need to know when an app is going away. Add a notification function to
> netlink that tells us that, and also hook it up to generic netlink so
> generic netlink can notify the families. Due to the way generic netlink
> works though, we need to notify all families and they have to sort out
> whatever resources some commands associated with the socket themselves.
> 

> @@ -166,6 +167,9 @@ static void netlink_sock_destruct(struct
>  		return;
>  	}
>  
> +	if (nlk->destruct)
> +		nlk->destruct(sk);
> +
>  	WARN_ON(atomic_read(&sk->sk_rmem_alloc));
>  	WARN_ON(atomic_read(&sk->sk_wmem_alloc));
>  	WARN_ON(nlk_sk(sk)->groups);


This seems pretty similar to the NETLINK_URELEASE notifier invoked
in netlink_release(). Wouldn't that one work as well?
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Johannes Berg Nov. 6, 2009, 3:26 p.m. UTC | #4
On Fri, 2009-11-06 at 16:21 +0100, Patrick McHardy wrote:
> Johannes Berg wrote:
> > When we want to keep track of resources associated with applications, we
> > need to know when an app is going away. Add a notification function to
> > netlink that tells us that, and also hook it up to generic netlink so
> > generic netlink can notify the families. Due to the way generic netlink
> > works though, we need to notify all families and they have to sort out
> > whatever resources some commands associated with the socket themselves.


> This seems pretty similar to the NETLINK_URELEASE notifier invoked
> in netlink_release(). Wouldn't that one work as well?

Hmm, it does seem similar, thanks for pointing it out. What exactly does
the condition
	if (nlk->pid && !nlk->subscriptions) {

mean though?

johannes
Patrick McHardy Nov. 6, 2009, 3:37 p.m. UTC | #5
Johannes Berg wrote:
> On Fri, 2009-11-06 at 16:21 +0100, Patrick McHardy wrote:
>> Johannes Berg wrote:
>>> When we want to keep track of resources associated with applications, we
>>> need to know when an app is going away. Add a notification function to
>>> netlink that tells us that, and also hook it up to generic netlink so
>>> generic netlink can notify the families. Due to the way generic netlink
>>> works though, we need to notify all families and they have to sort out
>>> whatever resources some commands associated with the socket themselves.
> 
> 
>> This seems pretty similar to the NETLINK_URELEASE notifier invoked
>> in netlink_release(). Wouldn't that one work as well?
> 
> Hmm, it does seem similar, thanks for pointing it out. What exactly does
> the condition
> 	if (nlk->pid && !nlk->subscriptions) {
> 
> mean though?

nlk->pid is non-zero for bound sockets, which is basically any
non-kernel socket which has either sent a message or explicitly
called bind(). nlk->subscriptions is zero for sockets not bound
to multicast groups.

So effectively it invokes the notifier for all bound unicast
userspace sockets. Not sure why it doesn't invoke the notifier
for sockets that are used for both unicast and multicast
reception. If that is a problem I think the second condition
could be removed.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Johannes Berg Nov. 9, 2009, 10:22 a.m. UTC | #6
On Fri, 2009-11-06 at 16:37 +0100, Patrick McHardy wrote:

> >> This seems pretty similar to the NETLINK_URELEASE notifier invoked
> >> in netlink_release(). Wouldn't that one work as well?
> > 
> > Hmm, it does seem similar, thanks for pointing it out. What exactly does
> > the condition
> > 	if (nlk->pid && !nlk->subscriptions) {
> > 
> > mean though?
> 
> nlk->pid is non-zero for bound sockets, which is basically any
> non-kernel socket which has either sent a message or explicitly
> called bind(). nlk->subscriptions is zero for sockets not bound
> to multicast groups.
> 
> So effectively it invokes the notifier for all bound unicast
> userspace sockets. Not sure why it doesn't invoke the notifier
> for sockets that are used for both unicast and multicast
> reception. If that is a problem I think the second condition
> could be removed.

Thanks for the explanation. I think we'd need the second condition
removed, I don't see a reason to force a socket to not also have
multicast RX if it's used for any of the purposes we're looking at this
for. Guess we need to audit the callees to determine whether that's ok.

Can you quickly explain the difference between release and destruct?

johannes
Patrick McHardy Nov. 9, 2009, 12:59 p.m. UTC | #7
Johannes Berg wrote:
> On Fri, 2009-11-06 at 16:37 +0100, Patrick McHardy wrote:
> 
>>>> This seems pretty similar to the NETLINK_URELEASE notifier invoked
>>>> in netlink_release(). Wouldn't that one work as well?
>>> Hmm, it does seem similar, thanks for pointing it out. What exactly does
>>> the condition
>>> 	if (nlk->pid && !nlk->subscriptions) {
>>>
>>> mean though?
>> nlk->pid is non-zero for bound sockets, which is basically any
>> non-kernel socket which has either sent a message or explicitly
>> called bind(). nlk->subscriptions is zero for sockets not bound
>> to multicast groups.
>>
>> So effectively it invokes the notifier for all bound unicast
>> userspace sockets. Not sure why it doesn't invoke the notifier
>> for sockets that are used for both unicast and multicast
>> reception. If that is a problem I think the second condition
>> could be removed.
> 
> Thanks for the explanation. I think we'd need the second condition
> removed, I don't see a reason to force a socket to not also have
> multicast RX if it's used for any of the purposes we're looking at this
> for. Guess we need to audit the callees to determine whether that's ok.

I've already done that. Its currently only used by netfilter
for which this change also makes sense.

> Can you quickly explain the difference between release and destruct?

release is called when the socket is closed, destruct is called
once all references are gone. I think with the synchonous processing
done nowadays they shouldn't make any difference, but release
should be fine in either case.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Johannes Berg Nov. 9, 2009, 1:03 p.m. UTC | #8
On Mon, 2009-11-09 at 13:59 +0100, Patrick McHardy wrote:

> > Thanks for the explanation. I think we'd need the second condition
> > removed, I don't see a reason to force a socket to not also have
> > multicast RX if it's used for any of the purposes we're looking at this
> > for. Guess we need to audit the callees to determine whether that's ok.
> 
> I've already done that. Its currently only used by netfilter
> for which this change also makes sense.

Cool, I arrived at that conclusion too, it seemed that it would
currently be somewhat strangely broken if you could add multicast groups
to those sockets used there. Not sure if you can though.

> > Can you quickly explain the difference between release and destruct?
> 
> release is called when the socket is closed, destruct is called
> once all references are gone. I think with the synchonous processing
> done nowadays they shouldn't make any difference, but release
> should be fine in either case.

Ok, cool, thanks. Do you want me to send the change removing the
multicast check, or would you want to do that since you audited all the
netlink callers?

Also, it's called URELEASE for unicast -- should we rename it to just
RELEASE?

johannes
Patrick McHardy Nov. 9, 2009, 1:19 p.m. UTC | #9
Johannes Berg wrote:
> On Mon, 2009-11-09 at 13:59 +0100, Patrick McHardy wrote:
> 
>>> Thanks for the explanation. I think we'd need the second condition
>>> removed, I don't see a reason to force a socket to not also have
>>> multicast RX if it's used for any of the purposes we're looking at this
>>> for. Guess we need to audit the callees to determine whether that's ok.
>> I've already done that. Its currently only used by netfilter
>> for which this change also makes sense.
> 
> Cool, I arrived at that conclusion too, it seemed that it would
> currently be somewhat strangely broken if you could add multicast groups
> to those sockets used there. Not sure if you can though.

I don't see anything preventing it.

>>> Can you quickly explain the difference between release and destruct?
>> release is called when the socket is closed, destruct is called
>> once all references are gone. I think with the synchonous processing
>> done nowadays they shouldn't make any difference, but release
>> should be fine in either case.
> 
> Ok, cool, thanks. Do you want me to send the change removing the
> multicast check, or would you want to do that since you audited all the
> netlink callers?

Please go ahead.

> Also, it's called URELEASE for unicast -- should we rename it to just
> RELEASE?

I think URELEASE is still fine since won't necessarily get called
for sockets that are used for pure multicast reception when using
setsockopt to bind to groups. I also have a cleanup patch removing
unneccessary nlk->pid checks from netfilter which would clash with
a rename :)
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Johannes Berg Nov. 9, 2009, 4:51 p.m. UTC | #10
On Mon, 2009-11-09 at 14:19 +0100, Patrick McHardy wrote:

> > Ok, cool, thanks. Do you want me to send the change removing the
> > multicast check, or would you want to do that since you audited all the
> > netlink callers?
> 
> Please go ahead.

Will do.

> > Also, it's called URELEASE for unicast -- should we rename it to just
> > RELEASE?
> 
> I think URELEASE is still fine since won't necessarily get called
> for sockets that are used for pure multicast reception when using
> setsockopt to bind to groups.

Oh? So on which sockets can I rely on it being used? After sending at
least one unicast message into the kernel? This seems to depend on pid
being assigned -- when is that?

johannes
Patrick McHardy Nov. 9, 2009, 4:57 p.m. UTC | #11
Johannes Berg wrote:
> On Mon, 2009-11-09 at 14:19 +0100, Patrick McHardy wrote:
> 
>>> Ok, cool, thanks. Do you want me to send the change removing the
>>> multicast check, or would you want to do that since you audited all the
>>> netlink callers?
>> Please go ahead.
> 
> Will do.
> 
>>> Also, it's called URELEASE for unicast -- should we rename it to just
>>> RELEASE?
>> I think URELEASE is still fine since won't necessarily get called
>> for sockets that are used for pure multicast reception when using
>> setsockopt to bind to groups.
> 
> Oh? So on which sockets can I rely on it being used? After sending at
> least one unicast message into the kernel? This seems to depend on pid
> being assigned -- when is that?

All unicast sockets that have either manually or automatically
bound. Automatic binding happens when sending the first message
or when calling connect().

Before that, your code can't know of the sockets existance, so
I guess this should be fine.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Johannes Berg Nov. 9, 2009, 5:46 p.m. UTC | #12
On Mon, 2009-11-09 at 17:57 +0100, Patrick McHardy wrote:

> > Oh? So on which sockets can I rely on it being used? After sending at
> > least one unicast message into the kernel? This seems to depend on pid
> > being assigned -- when is that?
> 
> All unicast sockets that have either manually or automatically
> bound. Automatic binding happens when sending the first message
> or when calling connect().
> 
> Before that, your code can't know of the sockets existance, so
> I guess this should be fine.

Ah, yes, of course... that's part of the boilerplate code to use generic
netlink so I always forget about what exactly is going on there :)

Thanks!

johannes
diff mbox

Patch

--- wireless-testing.orig/net/xfrm/xfrm_user.c	2009-09-23 10:10:41.000000000 +0200
+++ wireless-testing/net/xfrm/xfrm_user.c	2009-09-29 14:45:33.000000000 +0200
@@ -2605,7 +2605,7 @@  static int __net_init xfrm_user_net_init
 	struct sock *nlsk;
 
 	nlsk = netlink_kernel_create(net, NETLINK_XFRM, XFRMNLGRP_MAX,
-				     xfrm_netlink_rcv, NULL, THIS_MODULE);
+				     xfrm_netlink_rcv, NULL, NULL, THIS_MODULE);
 	if (nlsk == NULL)
 		return -ENOMEM;
 	rcu_assign_pointer(net->xfrm.nlsk, nlsk);
--- wireless-testing.orig/drivers/connector/connector.c	2009-09-29 12:26:17.000000000 +0200
+++ wireless-testing/drivers/connector/connector.c	2009-09-29 14:45:33.000000000 +0200
@@ -451,7 +451,7 @@  static int __devinit cn_init(void)
 
 	dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR,
 					 CN_NETLINK_USERS + 0xf,
-					 dev->input, NULL, THIS_MODULE);
+					 dev->input, NULL, NULL, THIS_MODULE);
 	if (!dev->nls)
 		return -EIO;
 
--- wireless-testing.orig/drivers/scsi/scsi_netlink.c	2009-09-23 10:10:42.000000000 +0200
+++ wireless-testing/drivers/scsi/scsi_netlink.c	2009-09-29 14:45:33.000000000 +0200
@@ -496,7 +496,7 @@  scsi_netlink_init(void)
 
 	scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT,
 				SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL,
-				THIS_MODULE);
+				NULL, THIS_MODULE);
 	if (!scsi_nl_sock) {
 		printk(KERN_ERR "%s: register of recieve handler failed\n",
 				__func__);
--- wireless-testing.orig/drivers/scsi/scsi_transport_iscsi.c	2009-09-29 12:26:46.000000000 +0200
+++ wireless-testing/drivers/scsi/scsi_transport_iscsi.c	2009-09-29 14:45:33.000000000 +0200
@@ -2082,7 +2082,7 @@  static __init int iscsi_transport_init(v
 		goto unregister_conn_class;
 
 	nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx,
-				    NULL, THIS_MODULE);
+				    NULL, NULL, THIS_MODULE);
 	if (!nls) {
 		err = -ENOBUFS;
 		goto unregister_session_class;
--- wireless-testing.orig/kernel/audit.c	2009-09-29 12:27:01.000000000 +0200
+++ wireless-testing/kernel/audit.c	2009-09-29 14:45:33.000000000 +0200
@@ -970,7 +970,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(&init_net, NETLINK_AUDIT, 0,
-					   audit_receive, NULL, THIS_MODULE);
+					   audit_receive, NULL, NULL,
+					   THIS_MODULE);
 	if (!audit_sock)
 		audit_panic("cannot initialize netlink socket");
 	else
--- wireless-testing.orig/lib/kobject_uevent.c	2009-09-23 10:10:42.000000000 +0200
+++ wireless-testing/lib/kobject_uevent.c	2009-09-29 14:45:33.000000000 +0200
@@ -322,7 +322,7 @@  EXPORT_SYMBOL_GPL(add_uevent_var);
 static int __init kobject_uevent_init(void)
 {
 	uevent_sock = netlink_kernel_create(&init_net, NETLINK_KOBJECT_UEVENT,
-					    1, NULL, NULL, THIS_MODULE);
+					    1, NULL, NULL, NULL, THIS_MODULE);
 	if (!uevent_sock) {
 		printk(KERN_ERR
 		       "kobject_uevent: unable to create netlink socket!\n");
--- wireless-testing.orig/net/bridge/netfilter/ebt_ulog.c	2009-09-29 12:27:03.000000000 +0200
+++ wireless-testing/net/bridge/netfilter/ebt_ulog.c	2009-09-29 14:45:33.000000000 +0200
@@ -304,7 +304,7 @@  static int __init ebt_ulog_init(void)
 
 	ebtulognl = netlink_kernel_create(&init_net, NETLINK_NFLOG,
 					  EBT_ULOG_MAXNLGROUPS, NULL, NULL,
-					  THIS_MODULE);
+					  NULL, THIS_MODULE);
 	if (!ebtulognl) {
 		printk(KERN_WARNING KBUILD_MODNAME ": out of memory trying to "
 		       "call netlink_kernel_create\n");
--- wireless-testing.orig/net/core/rtnetlink.c	2009-09-29 12:27:04.000000000 +0200
+++ wireless-testing/net/core/rtnetlink.c	2009-09-29 14:45:33.000000000 +0200
@@ -1360,7 +1360,8 @@  static int rtnetlink_net_init(struct net
 {
 	struct sock *sk;
 	sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX,
-				   rtnetlink_rcv, &rtnl_mutex, THIS_MODULE);
+				   rtnetlink_rcv, NULL,
+				   &rtnl_mutex, THIS_MODULE);
 	if (!sk)
 		return -ENOMEM;
 	net->rtnl = sk;
--- wireless-testing.orig/net/decnet/netfilter/dn_rtmsg.c	2009-09-23 10:10:41.000000000 +0200
+++ wireless-testing/net/decnet/netfilter/dn_rtmsg.c	2009-09-29 14:45:33.000000000 +0200
@@ -128,7 +128,7 @@  static int __init dn_rtmsg_init(void)
 
 	dnrmg = netlink_kernel_create(&init_net,
 				      NETLINK_DNRTMSG, DNRNG_NLGRP_MAX,
-				      dnrmg_receive_user_skb,
+				      dnrmg_receive_user_skb, NULL,
 				      NULL, THIS_MODULE);
 	if (dnrmg == NULL) {
 		printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket");
--- wireless-testing.orig/net/ipv4/fib_frontend.c	2009-09-23 10:10:42.000000000 +0200
+++ wireless-testing/net/ipv4/fib_frontend.c	2009-09-29 14:45:33.000000000 +0200
@@ -879,7 +879,7 @@  static int nl_fib_lookup_init(struct net
 {
 	struct sock *sk;
 	sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0,
-				   nl_fib_input, NULL, THIS_MODULE);
+				   nl_fib_input, NULL, NULL, THIS_MODULE);
 	if (sk == NULL)
 		return -EAFNOSUPPORT;
 	net->ipv4.fibnl = sk;
--- wireless-testing.orig/net/ipv4/inet_diag.c	2009-09-23 10:10:42.000000000 +0200
+++ wireless-testing/net/ipv4/inet_diag.c	2009-09-29 14:45:33.000000000 +0200
@@ -924,7 +924,7 @@  static int __init inet_diag_init(void)
 		goto out;
 
 	idiagnl = netlink_kernel_create(&init_net, NETLINK_INET_DIAG, 0,
-					inet_diag_rcv, NULL, THIS_MODULE);
+					inet_diag_rcv, NULL, NULL, THIS_MODULE);
 	if (idiagnl == NULL)
 		goto out_free_table;
 	err = 0;
--- wireless-testing.orig/net/ipv4/netfilter/ip_queue.c	2009-09-23 10:10:42.000000000 +0200
+++ wireless-testing/net/ipv4/netfilter/ip_queue.c	2009-09-29 14:45:33.000000000 +0200
@@ -578,7 +578,7 @@  static int __init ip_queue_init(void)
 
 	netlink_register_notifier(&ipq_nl_notifier);
 	ipqnl = netlink_kernel_create(&init_net, NETLINK_FIREWALL, 0,
-				      ipq_rcv_skb, NULL, THIS_MODULE);
+				      ipq_rcv_skb, NULL, NULL, THIS_MODULE);
 	if (ipqnl == NULL) {
 		printk(KERN_ERR "ip_queue: failed to create netlink socket\n");
 		goto cleanup_netlink_notifier;
--- wireless-testing.orig/net/ipv4/netfilter/ipt_ULOG.c	2009-09-23 10:10:42.000000000 +0200
+++ wireless-testing/net/ipv4/netfilter/ipt_ULOG.c	2009-09-29 14:45:33.000000000 +0200
@@ -400,9 +400,9 @@  static int __init ulog_tg_init(void)
 	for (i = 0; i < ULOG_MAXNLGROUPS; i++)
 		setup_timer(&ulog_buffers[i].timer, ulog_timer, i);
 
-	nflognl = netlink_kernel_create(&init_net,
-					NETLINK_NFLOG, ULOG_MAXNLGROUPS, NULL,
-					NULL, THIS_MODULE);
+	nflognl = netlink_kernel_create(&init_net, NETLINK_NFLOG,
+					ULOG_MAXNLGROUPS, NULL,
+					NULL, NULL, THIS_MODULE);
 	if (!nflognl)
 		return -ENOMEM;
 
--- wireless-testing.orig/net/ipv6/netfilter/ip6_queue.c	2009-09-23 10:10:42.000000000 +0200
+++ wireless-testing/net/ipv6/netfilter/ip6_queue.c	2009-09-29 14:45:33.000000000 +0200
@@ -580,7 +580,7 @@  static int __init ip6_queue_init(void)
 
 	netlink_register_notifier(&ipq_nl_notifier);
 	ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0,
-			              ipq_rcv_skb, NULL, THIS_MODULE);
+				      ipq_rcv_skb, NULL, NULL, THIS_MODULE);
 	if (ipqnl == NULL) {
 		printk(KERN_ERR "ip6_queue: failed to create netlink socket\n");
 		goto cleanup_netlink_notifier;
--- wireless-testing.orig/net/netfilter/nfnetlink.c	2009-09-29 12:27:12.000000000 +0200
+++ wireless-testing/net/netfilter/nfnetlink.c	2009-09-29 14:45:33.000000000 +0200
@@ -196,7 +196,7 @@  static int __init nfnetlink_init(void)
 	printk("Netfilter messages via NETLINK v%s.\n", nfversion);
 
 	nfnl = netlink_kernel_create(&init_net, NETLINK_NETFILTER, NFNLGRP_MAX,
-				     nfnetlink_rcv, NULL, THIS_MODULE);
+				     nfnetlink_rcv, NULL, NULL, THIS_MODULE);
 	if (!nfnl) {
 		printk(KERN_ERR "cannot initialize nfnetlink!\n");
 		return -ENOMEM;
--- wireless-testing.orig/net/netlink/genetlink.c	2009-09-29 12:27:12.000000000 +0200
+++ wireless-testing/net/netlink/genetlink.c	2009-09-29 14:45:33.000000000 +0200
@@ -561,6 +561,20 @@  static void genl_rcv(struct sk_buff *skb
 	genl_unlock();
 }
 
+static void genl_destruct(struct sock *sk)
+{
+	struct genl_family *f;
+	int idx;
+
+	genl_lock();
+
+	for (idx = 0; idx < GENL_FAM_TAB_SIZE; idx++)
+		list_for_each_entry(f, &family_ht[idx], family_list)
+			if (f->destruct_sk)
+				f->destruct_sk(sk);
+	genl_unlock();
+}
+
 /**************************************************************************
  * Controller
  **************************************************************************/
@@ -852,8 +866,8 @@  static int __net_init genl_pernet_init(s
 {
 	/* we'll bump the group number right afterwards */
 	net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, 0,
-					       genl_rcv, &genl_mutex,
-					       THIS_MODULE);
+					       genl_rcv, genl_destruct,
+					       &genl_mutex, THIS_MODULE);
 
 	if (!net->genl_sock && net_eq(net, &init_net))
 		panic("GENL: Cannot initialize generic netlink\n");
--- wireless-testing.orig/security/selinux/netlink.c	2009-09-23 10:10:42.000000000 +0200
+++ wireless-testing/security/selinux/netlink.c	2009-09-29 14:45:33.000000000 +0200
@@ -106,7 +106,8 @@  void selnl_notify_policyload(u32 seqno)
 static int __init selnl_init(void)
 {
 	selnl = netlink_kernel_create(&init_net, NETLINK_SELINUX,
-				      SELNLGRP_MAX, NULL, NULL, THIS_MODULE);
+				      SELNLGRP_MAX, NULL, NULL, NULL,
+				      THIS_MODULE);
 	if (selnl == NULL)
 		panic("SELinux:  Cannot create netlink socket.");
 	netlink_set_nonroot(NETLINK_SELINUX, NL_NONROOT_RECV);
--- wireless-testing.orig/include/linux/netlink.h	2009-09-29 12:26:58.000000000 +0200
+++ wireless-testing/include/linux/netlink.h	2009-09-29 14:45:33.000000000 +0200
@@ -182,6 +182,7 @@  extern void netlink_table_ungrab(void);
 extern struct sock *netlink_kernel_create(struct net *net,
 					  int unit,unsigned int groups,
 					  void (*input)(struct sk_buff *skb),
+					  void (*destruct)(struct sock *sk),
 					  struct mutex *cb_mutex,
 					  struct module *module);
 extern void netlink_kernel_release(struct sock *sk);
--- wireless-testing.orig/include/net/genetlink.h	2009-09-23 10:10:42.000000000 +0200
+++ wireless-testing/include/net/genetlink.h	2009-09-29 14:45:33.000000000 +0200
@@ -30,6 +30,8 @@  struct genl_multicast_group
  * @maxattr: maximum number of attributes supported
  * @netnsok: set to true if the family can handle network
  *	namespaces and should be presented in all of them
+ * @destruct_sk: called when any generic netlink socket
+ *	is destroyed (e.g. by the application closing it)
  * @attrbuf: buffer to store parsed attributes
  * @ops_list: list of all assigned operations
  * @family_list: family list
@@ -43,6 +45,7 @@  struct genl_family
 	unsigned int		version;
 	unsigned int		maxattr;
 	bool			netnsok;
+	void			(*destruct_sk)(struct sock *sk);
 	struct nlattr **	attrbuf;	/* private */
 	struct list_head	ops_list;	/* private */
 	struct list_head	family_list;	/* private */
--- wireless-testing.orig/net/netlink/af_netlink.c	2009-09-29 12:27:12.000000000 +0200
+++ wireless-testing/net/netlink/af_netlink.c	2009-09-29 14:45:33.000000000 +0200
@@ -80,6 +80,7 @@  struct netlink_sock {
 	struct mutex		*cb_mutex;
 	struct mutex		cb_def_mutex;
 	void			(*netlink_rcv)(struct sk_buff *skb);
+	void			(*destruct)(struct sock *sk);
 	struct module		*module;
 };
 
@@ -166,6 +167,9 @@  static void netlink_sock_destruct(struct
 		return;
 	}
 
+	if (nlk->destruct)
+		nlk->destruct(sk);
+
 	WARN_ON(atomic_read(&sk->sk_rmem_alloc));
 	WARN_ON(atomic_read(&sk->sk_wmem_alloc));
 	WARN_ON(nlk_sk(sk)->groups);
@@ -1464,6 +1468,7 @@  static void netlink_data_ready(struct so
 struct sock *
 netlink_kernel_create(struct net *net, int unit, unsigned int groups,
 		      void (*input)(struct sk_buff *skb),
+		      void (*destruct)(struct sock *sk),
 		      struct mutex *cb_mutex, struct module *module)
 {
 	struct socket *sock;
@@ -1502,6 +1507,7 @@  netlink_kernel_create(struct net *net, i
 	sk->sk_data_ready = netlink_data_ready;
 	if (input)
 		nlk_sk(sk)->netlink_rcv = input;
+	nlk_sk(sk)->destruct = destruct;
 
 	if (netlink_insert(sk, net, 0))
 		goto out_sock_release;