Netdev List
 help / color / mirror / Atom feed
* [PATCH v2] socket: don't return uninitialized addresses on concurrent socket shutdown
From: Hannes Frederic Sowa @ 2013-11-16  5:48 UTC (permalink / raw)
  To: mpb, netdev
In-Reply-To: <20131116054344.GG26901@order.stressinduktion.org>

If a blocking read waits on a socket which gets concurrently shut down we
return 0 as error and so indicate success to the socket functions which
thus copy an uninitialized stack allocated address back to the user.
Fix this by clearing the 128 byte size (on x86-64) address first.

This patch fixes the problem for recvfrom, recvmsg and recvmmsg.

Reported-by: mpb <mpb.mail@gmail.com>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
Sorry, grabbed the wrong patch file.

 net/socket.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/net/socket.c b/net/socket.c
index c226ace..a44f29c 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1834,6 +1834,8 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
 	if (!sock)
 		goto out;
 
+	if (addr != NULL)
+		memset(&address, 0, sizeof(address));
 	msg.msg_control = NULL;
 	msg.msg_controllen = 0;
 	msg.msg_iovlen = 1;
@@ -2228,6 +2230,8 @@ static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
 
 	uaddr = (__force void __user *)msg_sys->msg_name;
 	uaddr_len = COMPAT_NAMELEN(msg);
+	if (uaddr != NULL)
+		memset(&addr, 0, sizeof(addr));
 	if (MSG_CMSG_COMPAT & flags) {
 		err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE);
 	} else
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH net RESEND] bonding: don't change to 802.3ad mode while ARP monitoring is running
From: Ding Tianhong @ 2013-11-16  6:30 UTC (permalink / raw)
  To: Jay Vosburgh, Andy Gospodarek, David S. Miller,
	Nikolay Aleksandrov, Veaceslav Falico, Netdev

Because the ARP monitoring is not support for 802.3ad, but I still
could change the mode to 802.3ad from ab mode while ARP monitoring
is running, it is incorrect.

So add a check for 802.3ad in bonding_store_mode to fix the problem,
and make a new macro BOND_NO_USES_ARP() to simplify the code.

Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
---
 drivers/net/bonding/bond_options.c | 2 +-
 drivers/net/bonding/bonding.h      | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 9a5223c..abb4218 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -45,7 +45,7 @@ int bond_option_mode_set(struct bonding *bond, int mode)
 		return -EPERM;
 	}
 
-	if (BOND_MODE_IS_LB(mode) && bond->params.arp_interval) {
+	if (BOND_NO_USES_ARP(mode) && bond->params.arp_interval) {
 		pr_err("%s: %s mode is incompatible with arp monitoring.\n",
 		       bond->dev->name, bond_mode_tbl[mode].modename);
 		return -EINVAL;
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 046a605..e2c11cb 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -63,6 +63,10 @@
 		(((mode) == BOND_MODE_TLB) ||	\
 		 ((mode) == BOND_MODE_ALB))
 
+#define BOND_NO_USES_ARP(mode)				\
+		(((mode) == BOND_MODE_8023AD)	||	\
+		 ((mode) == BOND_MODE_TLB)	||	\
+		 ((mode) == BOND_MODE_ALB))
 /*
  * Less bad way to call ioctl from within the kernel; this needs to be
  * done some other way to get the call out of interrupt context.
-- 
1.7.12

^ permalink raw reply related

* Re: [PATCH v2] socket: don't return uninitialized addresses on concurrent socket shutdown
From: Eric Dumazet @ 2013-11-16  6:32 UTC (permalink / raw)
  To: Hannes Frederic Sowa; +Cc: mpb, netdev
In-Reply-To: <20131116054814.GH26901@order.stressinduktion.org>

On Sat, 2013-11-16 at 06:48 +0100, Hannes Frederic Sowa wrote:
> If a blocking read waits on a socket which gets concurrently shut down we
> return 0 as error and so indicate success to the socket functions which
> thus copy an uninitialized stack allocated address back to the user.
> Fix this by clearing the 128 byte size (on x86-64) address first.
> 
> This patch fixes the problem for recvfrom, recvmsg and recvmmsg.
> 
> Reported-by: mpb <mpb.mail@gmail.com>
> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
> ---

Are you clearing 128 bytes on every recvfrom() system call, just in case
of this shutdown() issue ?

Can't we avoid this overhead ?

msg.msg_namelen should be set to 0 in this case.

^ permalink raw reply

* Re: [PATCH v2] socket: don't return uninitialized addresses on concurrent socket shutdown
From: Hannes Frederic Sowa @ 2013-11-16  6:39 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: mpb, netdev
In-Reply-To: <1384583569.8604.4.camel@edumazet-glaptop2.roam.corp.google.com>

On Fri, Nov 15, 2013 at 10:32:49PM -0800, Eric Dumazet wrote:
> On Sat, 2013-11-16 at 06:48 +0100, Hannes Frederic Sowa wrote:
> > If a blocking read waits on a socket which gets concurrently shut down we
> > return 0 as error and so indicate success to the socket functions which
> > thus copy an uninitialized stack allocated address back to the user.
> > Fix this by clearing the 128 byte size (on x86-64) address first.
> > 
> > This patch fixes the problem for recvfrom, recvmsg and recvmmsg.
> > 
> > Reported-by: mpb <mpb.mail@gmail.com>
> > Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
> > ---
> 
> Are you clearing 128 bytes on every recvfrom() system call, just in case
> of this shutdown() issue ?

Yes, that gave me a bad feeling, too (so I explicitly mentioned it in the
changelog and hoped for some discussion).

> Can't we avoid this overhead ?
> 
> msg.msg_namelen should be set to 0 in this case.

I don't see how, currently. Either we tunnel a new return value through
->recvmsg or we use the address structure, mark it with a special AF_FOO and
check if we get back that same value.

I don't see how msg.msg_namelen set to zero can help?

^ permalink raw reply

* Re: [PATCH v2] socket: don't return uninitialized addresses on concurrent socket shutdown
From: Hannes Frederic Sowa @ 2013-11-16  6:42 UTC (permalink / raw)
  To: Eric Dumazet, mpb, netdev
In-Reply-To: <20131116063956.GI26901@order.stressinduktion.org>

On Sat, Nov 16, 2013 at 07:39:56AM +0100, Hannes Frederic Sowa wrote:
> On Fri, Nov 15, 2013 at 10:32:49PM -0800, Eric Dumazet wrote:
> > On Sat, 2013-11-16 at 06:48 +0100, Hannes Frederic Sowa wrote:
> > > If a blocking read waits on a socket which gets concurrently shut down we
> > > return 0 as error and so indicate success to the socket functions which
> > > thus copy an uninitialized stack allocated address back to the user.
> > > Fix this by clearing the 128 byte size (on x86-64) address first.
> > > 
> > > This patch fixes the problem for recvfrom, recvmsg and recvmmsg.
> > > 
> > > Reported-by: mpb <mpb.mail@gmail.com>
> > > Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
> > > ---
> > 
> > Are you clearing 128 bytes on every recvfrom() system call, just in case
> > of this shutdown() issue ?
> 
> Yes, that gave me a bad feeling, too (so I explicitly mentioned it in the
> changelog and hoped for some discussion).
> 
> > Can't we avoid this overhead ?
> > 
> > msg.msg_namelen should be set to 0 in this case.
> 
> I don't see how, currently. Either we tunnel a new return value through
> ->recvmsg or we use the address structure, mark it with a special AF_FOO and
> check if we get back that same value.
> 
> I don't see how msg.msg_namelen set to zero can help?

We could also think about changing the return value on concurrent closed
sockets entirely and avoiding this whole issue. It would only change
concurrent shutdown()/read() behaviour, not close as far as I can see.

^ permalink raw reply

* Re: [PATCH v3] net: Do not include padding in TCP GRO checksum
From: Herbert Xu @ 2013-11-16  6:46 UTC (permalink / raw)
  To: Alexander Duyck; +Cc: Alexander Duyck, davem, netdev, edumazet
In-Reply-To: <5286F018.8060801@gmail.com>

On Fri, Nov 15, 2013 at 08:10:00PM -0800, Alexander Duyck wrote:
>
> The case I am addressing is padding added by the remote side. 
> Specifically in my case I was seeing TCP frames without options that
> were padded up to 60 bytes from a netperf TCP_RR test.  I messed up the
> padding/checksum logic so it was making the same mistake in the Tx
> checksum logic in the driver that I caught here in GRO.  As a result I
> was seeing checksum errors errors in wireshark, but noticed they were
> being accepted by the stack as valid.

OK great.  So this isn't normal data that we expect to aggregate.

In that case the simplest solution is to skip the checksum check
altogether.  We only require it if the packet is going to be merged.

So how about something like this?

gro: Only verify TCP checksums for candidates

In some cases we may receive IP packets that are longer than
their stated lengths.  Such packets are never merged in GRO.
However, we may end up computing their checksums incorrectly
and end up allowing packets with a bogus checksum enter our
stack with the checksum status set as verified.

Since such packets are rare and not performance-critical, this
patch simply skips the checksum verification for them.

Reported-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index a2b68a1..55aeec9 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -276,6 +276,10 @@ static struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *
 	__wsum wsum;
 	__sum16 sum;
 
+	/* Don't bother verifying checksum if we're going to flush anyway. */
+	if (NAPI_GRO_CB(skb)->flush)
+		goto skip_csum;
+
 	switch (skb->ip_summed) {
 	case CHECKSUM_COMPLETE:
 		if (!tcp_v4_check(skb_gro_len(skb), iph->saddr, iph->daddr,
@@ -301,6 +305,7 @@ flush:
 		break;
 	}
 
+skip_csum:
 	return tcp_gro_receive(head, skb);
 }
 
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c
index c1097c7..71923d1 100644
--- a/net/ipv6/tcpv6_offload.c
+++ b/net/ipv6/tcpv6_offload.c
@@ -39,6 +39,10 @@ static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
 	__wsum wsum;
 	__sum16 sum;
 
+	/* Don't bother verifying checksum if we're going to flush anyway. */
+	if (NAPI_GRO_CB(skb)->flush)
+		goto skip_csum;
+
 	switch (skb->ip_summed) {
 	case CHECKSUM_COMPLETE:
 		if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
@@ -65,6 +69,7 @@ flush:
 		break;
 	}
 
+skip_csum:
 	return tcp_gro_receive(head, skb);
 }

Thanks,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply related

* Re: [PATCH v3] net: Do not include padding in TCP GRO checksum
From: Herbert Xu @ 2013-11-16  7:23 UTC (permalink / raw)
  To: Alexander Duyck; +Cc: Alexander Duyck, davem, netdev, edumazet
In-Reply-To: <20131116064611.GA12146@gondor.apana.org.au>

On Sat, Nov 16, 2013 at 02:46:11PM +0800, Herbert Xu wrote:
> 
> gro: Only verify TCP checksums for candidates

And here is a patch on top of it that simplifies the checksum
code.

gro: Clean up tcpX_gro_receive checksum verification
    
This patch simplifies the checksum verification in tcpX_gro_receive
by reusing the CHECKSUM_COMPLETE code for CHECKSUM_NONE.  All it
does for CHECKSUM_NONE is compute the partial checksum and then
treat it as if it came from the hardware (CHECKSUM_COMPLETE).
    
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index 55aeec9..0560635 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -274,35 +274,29 @@ static struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *
 {
 	const struct iphdr *iph = skb_gro_network_header(skb);
 	__wsum wsum;
-	__sum16 sum;
 
 	/* Don't bother verifying checksum if we're going to flush anyway. */
 	if (NAPI_GRO_CB(skb)->flush)
 		goto skip_csum;
 
+	wsum = skb->csum;
+
 	switch (skb->ip_summed) {
+	case CHECKSUM_NONE:
+		wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb),
+				    0);
+
+		/* fall through */
+
 	case CHECKSUM_COMPLETE:
 		if (!tcp_v4_check(skb_gro_len(skb), iph->saddr, iph->daddr,
-				  skb->csum)) {
+				  wsum)) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			break;
 		}
-flush:
+
 		NAPI_GRO_CB(skb)->flush = 1;
 		return NULL;
-
-	case CHECKSUM_NONE:
-		wsum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
-					  skb_gro_len(skb), IPPROTO_TCP, 0);
-		sum = csum_fold(skb_checksum(skb,
-					     skb_gro_offset(skb),
-					     skb_gro_len(skb),
-					     wsum));
-		if (sum)
-			goto flush;
-
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-		break;
 	}
 
 skip_csum:
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c
index 71923d1..6d18157 100644
--- a/net/ipv6/tcpv6_offload.c
+++ b/net/ipv6/tcpv6_offload.c
@@ -37,36 +37,29 @@ static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
 {
 	const struct ipv6hdr *iph = skb_gro_network_header(skb);
 	__wsum wsum;
-	__sum16 sum;
 
 	/* Don't bother verifying checksum if we're going to flush anyway. */
 	if (NAPI_GRO_CB(skb)->flush)
 		goto skip_csum;
 
+	wsum = skb->csum;
+
 	switch (skb->ip_summed) {
+	case CHECKSUM_NONE:
+		wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb),
+				    wsum);
+
+		/* fall through */
+
 	case CHECKSUM_COMPLETE:
 		if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
-				  skb->csum)) {
+				  wsum)) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			break;
 		}
-flush:
+
 		NAPI_GRO_CB(skb)->flush = 1;
 		return NULL;
-
-	case CHECKSUM_NONE:
-		wsum = ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr,
-						    skb_gro_len(skb),
-						    IPPROTO_TCP, 0));
-		sum = csum_fold(skb_checksum(skb,
-					     skb_gro_offset(skb),
-					     skb_gro_len(skb),
-					     wsum));
-		if (sum)
-			goto flush;
-
-		skb->ip_summed = CHECKSUM_UNNECESSARY;
-		break;
 	}
 
 skip_csum:

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply related

* Re: [PATCH] random: seed random_int_secret at least poorly at core_initcall time
From: Hannes Frederic Sowa @ 2013-11-16  7:40 UTC (permalink / raw)
  To: Kees Cook
  Cc: Theodore Ts'o, Daniel Borkmann, David S. Miller,
	shemminger-OTpzqLSitTUnbdJkjeBofR2eb7JE58TQ, Florian Weimer,
	netdev-u79uwXL29TY76Z2rM5mHXA, Eric Dumazet,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <CAGXu5jJJtjvAqROzsekOd9Y5wbiw=G9ToNryOfP8auhQRrYORw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Fri, Nov 15, 2013 at 10:42:28AM -0800, Kees Cook wrote:
> On Wed, Nov 13, 2013 at 8:18 PM, Hannes Frederic Sowa
> <hannes-tFNcAqjVMyqKXQKiL6tip0B+6BGkLq7r@public.gmane.org> wrote:
> > On Wed, Nov 13, 2013 at 09:54:48PM -0500, Theodore Ts'o wrote:
> >> On Tue, Nov 12, 2013 at 02:46:03PM +0100, Hannes Frederic Sowa wrote:
> >> > > It is needed by fork to set up the stack canary. And this actually gets
> >> > > called before the secret is initialized.
> >> >
> >> > Maybe we could use this for the time being and use the seeding method
> >> > of kaslr as soon as it hits the tree?
> >>
> >> Hmm, from what I can tell even early_initcall() is going to be early
> >> enough.  The stack canary is set up by boot_init_stack_canary(), which
> >> is run very, very early in start_kerne() --- way before
> >> early_initcalls, or even before interrupts are enabled.  So adding
> >> random_int_secret_init_early() as a core_initcall is still too late.
> >
> > Actually I tried to protect the tsk->stack_canary = get_random_int()
> > in fork.c. It sets up the per-task canary.
> 
> I haven't looked closely yet at how the stack canary gets plumbed, but
> what do things outside of process context end up using?

Early on boot __stack_chk_guard gets initialized. The address of this symbol
is looked up by gcc to assemble the stack guard checks.

Only on ARM with !CONFIG_SMP the __stack_chk_guard is switched as soon
as a new process context is entered. This is not possible if the kernel
is compiled for CONFIG_SMP and the kernel will fallback to the one global
__stack_chk_guard canary.

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

^ permalink raw reply

* Re: [PATCH net-next 4/4] virtio-net: auto-tune mergeable rx buffer size for improved performance
From: Michael Dalton @ 2013-11-16  9:06 UTC (permalink / raw)
  To: Michael S. Tsirkin
  Cc: netdev, Eric Dumazet, lf-virt, Daniel Borkmann, David S. Miller
In-Reply-To: <20131113174245.GB31078@redhat.com>

Hi,

Apologies for the delay, I wanted to get answers together for all of the
open questions raised on this thread. The first patch in this patchset is
already merged, so after the merge window re-opens I'll send out new
patchsets covering the remaining 3 patches.

After reflecting on feedback from this thread, I think it makes sense to
separate out the per-receive queue page frag allocator patches from the
autotuning patch when the merge window re-opens. The per-receive queue
page frag allocator patches help deal with fragmentation (PAGE_SIZE does
not evenly divide MERGE_BUFFER_LEN), and provide benefits whether or not
auto-tuning is present. Auto-tuning can then be evaluated separately.

On Wed, 2013-11-13 at 15:10 +0800, Jason Wang wrote:
> There's one concern with EWMA. How well does it handle multiple streams
> each with different packet size? E.g there may be two flows, one with
> 256 bytes each packet another is 64K.  Looks like it can result we
> allocate PAGE_SIZE buffer for 256 (which is bad since the
> payload/truesize is low) bytes or 1500+ for 64K buffer (which is ok
> since we can do coalescing).

If multiple streams of very different packet sizes are arriving on the
same receive queue, no single buffer size is ideal(e.g., large buffers
will cause small packets to take up too much memory, but small buffers
may reduce throughput somewhat for large packets). We don't know a
priori which packet will be delivered to a given receive queue packet
buffer, so any size we choose will not be optimal for all cases if we
have significant variance in packet sizes.

> Do you have perf numbers that just without this patch? We need to know
> how much EWMA help exactly.

Great point, I should have included that in my initial benchmarking. I ran
a benchmark in the same environment as my initial results, this time with
the first 3 patches in this patchset applied but without the autotuning
patch.  The average performance over 5 runs of 30-second netperf was
13760.85Gb/s.

> Is there a chance that est_buffer_len was smaller than or equal with len?

Yes, that is possible if the average packet length decreases.

> Not sure this is accurate, since buflen may change and several frags may
> share a single page. So the est_buffer_len we get in receive_mergeable()
> may not be the correct value.

I agree it may not be 100% accurate but we can choose a weight that will
cause the average packet size to change slowly. Even with an order 3 page
there will not be too many packet buffers allocated from a single page.

On Wed, 2013-11-13 at 17:42 +0800, Michael S. Tsirkin wrote:
> I'm not sure it's useful - no one is likely to tune it in practice.
> But how about a comment explaining how was the number chosen?

That makes sense, I agree a comment is needed. The weight determines
how quickly we react to a change in packet size. As we attempt to fill
all free ring entries on refill (in try_fill_recv), I chose a large
weight so that a short burst of traffic with a different average packet
size will not substantially shift the packet buffer size for the entire
ring the next time try_fill_recv is called. I'll add a comment that
compares 64 to nearby values (32, 16).

Best,

Mike

^ permalink raw reply

* Re: Kernel 3.4.57: "tg3 0000:01:00.0: eth0: transmit timed out, resetting"
From: Bjorn Helgaas @ 2013-11-16 15:09 UTC (permalink / raw)
  To: Urban Loesch
  Cc: linux-kernel@vger.kernel.org, Nithin Nayak Sujir, Michael Chan,
	netdev
In-Reply-To: <52877AB3.1080201@enas.net>

[+cc Nithin, Michael, netdev]

On Sat, Nov 16, 2013 at 7:01 AM, Urban Loesch <bind@enas.net> wrote:
> Hi,
>
> I'm running a DELL PER620 with kernel 3.4.57 an Broadcom quad-port gbit
> adapter BCM5720. 15min load-average is about 4-8.
>
> After 13 days of uptime today the machine becomes unresponsible. But after a
> couple of minutes it becomes responsible again and was rebooted (sysctl
> paremter for kernel.panic = 1) automatically. the machine is acting a
> webserver fo about 3000 virtualhosts.
>
> After searching the lofiles on remote my syslog server I found the following
> messages regarding eth0:
>
> 2013-11-16 11:43:38  [1505491.196172] tg3 0000:01:00.0: eth0: transmit timed
> out, resetting
> 2013-11-16 11:43:38  [1505491.815002] INFO: rcu_bh detected stalls on
> CPUs/tasks:
> 2013-11-16 11:43:38  [1505491.815009]   16: (1 GPs behind)
> idle=1fd/140000000000000/0
> 2013-11-16 11:43:38  [1505491.815012]   (detected by 6, t=6002 jiffies)
> 2013-11-16 11:43:38  [1505491.815014] INFO: Stall ended before state dump
> start
> 2013-11-16 11:43:38  [1505492.450611] tg3 0000:01:00.0: eth0: 0x00000000:
> 0x165f14e4, 0x00100406, 0x02000000, 0x00800010
> 2013-11-16 11:43:38  [1505492.450614] tg3 0000:01:00.0: eth0: 0x00000010:
> 0xd57a000c, 0x00000000, 0xd57b000c, 0x00000000
> 2013-11-16 11:43:38  [1505492.450615] tg3 0000:01:00.0: eth0: 0x00000020:
> 0xd57c000c, 0x00000000, 0x00000000, 0x1f5b1028
> 2013-11-16 11:43:38  [1505492.450617] tg3 0000:01:00.0: eth0: 0x00000030:
> 0xd8800000, 0x00000048, 0x00000000, 0x0000010f
> 2013-11-16 11:43:38  [1505492.450619] tg3 0000:01:00.0: eth0: 0x00000040:
> 0x00000000, 0x3f000000, 0xc8035001, 0x64002008
> 2013-11-16 11:43:38  [1505492.450621] tg3 0000:01:00.0: eth0: 0x00000050:
> 0x818c5803, 0x78000000, 0x0086a005, 0x00000000
> 2013-11-16 11:43:38  [1505492.450623] tg3 0000:01:00.0: eth0: 0x00000060:
> 0x00000000, 0x00000000, 0xf0000298, 0x00380081
> 2013-11-16 11:43:38  [1505492.450624] tg3 0000:01:00.0: eth0: 0x00000070:
> 0x000710b0, 0xffcb28fa, 0x0001421c, 0x00000000
> 2013-11-16 11:43:38  [1505492.450626] tg3 0000:01:00.0: eth0: 0x00000080:
> 0x00000001, 0x00000002, 0x00000000, 0x000001d2
> 2013-11-16 11:43:38  [1505492.450628] tg3 0000:01:00.0: eth0: 0x00000090:
> 0x00000000, 0x00000000, 0x00000000, 0x000006a1
> 2013-11-16 11:43:38  [1505492.450629] tg3 0000:01:00.0: eth0: 0x000000a0:
> 0x8010ac11, 0x00000004, 0x00001004, 0x00020010
> 2013-11-16 11:43:38  [1505492.450631] tg3 0000:01:00.0: eth0: 0x000000b0:
> 0x10008d81, 0x0010242e, 0x0004cc22, 0x10120040
> 2013-11-16 11:43:38  [1505492.450633] tg3 0000:01:00.0: eth0: 0x000000d0:
> 0x0000001f, 0x00000006, 0x00000000, 0x00000001
> 2013-11-16 11:43:38  [1505492.450635] tg3 0000:01:00.0: eth0: 0x000000f0:
> 0x00000000, 0x05720000, 0x00000000, 0xbec733be
> 2013-11-16 11:43:38  [1505492.450637] tg3 0000:01:00.0: eth0: 0x00000100:
> 0x13c10001, 0x00000000, 0x00018000, 0x000e7030
> 2013-11-16 11:43:38  [1505492.450638] tg3 0000:01:00.0: eth0: 0x00000110:
> 0x00002000, 0x000031c0, 0x000000a0, 0x00000000
> 2013-11-16 11:43:38  [1505492.450640] tg3 0000:01:00.0: eth0: 0x00000130:
> 0x00000000, 0x00000000, 0x00000000, 0x15010003
> 2013-11-16 11:43:38  [1505492.450642] tg3 0000:01:00.0: eth0: 0x00000140:
> 0x1c3f67fa, 0x000090b1, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450643] tg3 0000:01:00.0: eth0: 0x00000150:
> 0x16010004, 0x00000000, 0x0007811b, 0x00000001
> 2013-11-16 11:43:38  [1505492.450645] tg3 0000:01:00.0: eth0: 0x00000160:
> 0x00010002, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450647] tg3 0000:01:00.0: eth0: 0x00000170:
> 0x00000000, 0x800000ff, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450648] tg3 0000:01:00.0: eth0: 0x00000200:
> 0x00000000, 0x3f000000, 0x00000000, 0xfb000000
> 2013-11-16 11:43:38  [1505492.450650] tg3 0000:01:00.0: eth0: 0x00000210:
> 0x00000000, 0x0d000000, 0x00000000, 0xa7000000
> 2013-11-16 11:43:38  [1505492.450652] tg3 0000:01:00.0: eth0: 0x00000220:
> 0x00000000, 0x00000001, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450653] tg3 0000:01:00.0: eth0: 0x00000260:
> 0x00000000, 0x00000000, 0x00000000, 0x000006a1
> 2013-11-16 11:43:38  [1505492.450655] tg3 0000:01:00.0: eth0: 0x00000280:
> 0x00000000, 0x000001d2, 0x00000000, 0x00000d73
> 2013-11-16 11:43:38  [1505492.450657] tg3 0000:01:00.0: eth0: 0x00000290:
> 0x00000000, 0x000004df, 0x00000000, 0x000001b5
> 2013-11-16 11:43:38  [1505492.450659] tg3 0000:01:00.0: eth0: 0x00000300:
> 0x0000010d, 0x000001df, 0x000000bb, 0x00000035
> 2013-11-16 11:43:38  [1505492.450660] tg3 0000:01:00.0: eth0: 0x00000400:
> 0x18e04808, 0x00400000, 0x00001000, 0x00000880
> 2013-11-16 11:43:38  [1505492.450662] tg3 0000:01:00.0: eth0: 0x00000410:
> 0x000090b1, 0x1c3f67fa, 0x000090b1, 0x1c3f67fa
> 2013-11-16 11:43:38  [1505492.450664] tg3 0000:01:00.0: eth0: 0x00000420:
> 0x000090b1, 0x1c3f67fa, 0x000090b1, 0x1c3f67fa
> 2013-11-16 11:43:38  [1505492.450666] tg3 0000:01:00.0: eth0: 0x00000430:
> 0x00000400, 0x00000000, 0x000002f4, 0x000005f2
> 2013-11-16 11:43:38  [1505492.450667] tg3 0000:01:00.0: eth0: 0x00000440:
> 0x00000000, 0x00000000, 0x00000000, 0x04384400
> 2013-11-16 11:43:38  [1505492.450669] tg3 0000:01:00.0: eth0: 0x00000450:
> 0x00000001, 0x00008000, 0x00000000, 0x00000102
> 2013-11-16 11:43:38  [1505492.450671] tg3 0000:01:00.0: eth0: 0x00000460:
> 0x00000008, 0x00002620, 0x01ff0002, 0x00000000
> 2013-11-16 11:43:38  [1505492.450672] tg3 0000:01:00.0: eth0: 0x00000470:
> 0x80000200, 0x00c10000, 0x01000000, 0xc0000000
> 2013-11-16 11:43:38  [1505492.450674] tg3 0000:01:00.0: eth0: 0x00000480:
> 0x42000000, 0x7fffffff, 0x06000004, 0x7fffffff
> 2013-11-16 11:43:38  [1505492.450676] tg3 0000:01:00.0: eth0: 0x00000500:
> 0x00000008, 0x00000002, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450677] tg3 0000:01:00.0: eth0: 0x00000540:
> 0x0000e0db, 0x551fe086, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450679] tg3 0000:01:00.0: eth0: 0x00000590:
> 0x00e00000, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450681] tg3 0000:01:00.0: eth0: 0x000005b0:
> 0x00000000, 0x00000008, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450682] tg3 0000:01:00.0: eth0: 0x000005c0:
> 0x52ad2878, 0x40ae6aee, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450684] tg3 0000:01:00.0: eth0: 0x00000600:
> 0xffffffff, 0x00f80011, 0x00000000, 0x00001f04
> 2013-11-16 11:43:38  [1505492.450686] tg3 0000:01:00.0: eth0: 0x00000610:
> 0xffffffff, 0x00000000, 0x07c00004, 0x00000000
> 2013-11-16 11:43:38  [1505492.450687] tg3 0000:01:00.0: eth0: 0x00000620:
> 0x00000040, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450689] tg3 0000:01:00.0: eth0: 0x00000630:
> 0x01230123, 0x01230123, 0x01230123, 0x01230123
> 2013-11-16 11:43:38  [1505492.450691] tg3 0000:01:00.0: eth0: 0x00000640:
> 0x01230123, 0x01230123, 0x01230123, 0x01230123
> 2013-11-16 11:43:38  [1505492.450693] tg3 0000:01:00.0: eth0: 0x00000650:
> 0x01230123, 0x01230123, 0x01230123, 0x01230123
> 2013-11-16 11:43:38  [1505492.450694] tg3 0000:01:00.0: eth0: 0x00000660:
> 0x01230123, 0x01230123, 0x01230123, 0x01230123
> 2013-11-16 11:43:38  [1505492.450696] tg3 0000:01:00.0: eth0: 0x00000670:
> 0x5f865437, 0xe4ac62cc, 0x50103a45, 0x36621985
> 2013-11-16 11:43:38  [1505492.450698] tg3 0000:01:00.0: eth0: 0x00000680:
> 0xbf14c0e8, 0x1bc27a1e, 0x84f4b556, 0x094ea6fe
> 2013-11-16 11:43:38  [1505492.450699] tg3 0000:01:00.0: eth0: 0x00000690:
> 0x7dda01e7, 0xc04d7481, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450701] tg3 0000:01:00.0: eth0: 0x000006c0:
> 0x00000000, 0x00000000, 0x04000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450703] tg3 0000:01:00.0: eth0: 0x000006d0:
> 0x00000001, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450705] tg3 0000:01:00.0: eth0: 0x00000800:
> 0x000008a6, 0xffffffff, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450706] tg3 0000:01:00.0: eth0: 0x00000810:
> 0x00000000, 0xffffffff, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450708] tg3 0000:01:00.0: eth0: 0x00000820:
> 0x00000000, 0x00000000, 0xffffffff, 0x00000000
> 2013-11-16 11:43:38  [1505492.450710] tg3 0000:01:00.0: eth0: 0x00000830:
> 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff
> 2013-11-16 11:43:38  [1505492.450711] tg3 0000:01:00.0: eth0: 0x00000840:
> 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
> 2013-11-16 11:43:38  [1505492.450713] tg3 0000:01:00.0: eth0: 0x00000850:
> 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
> 2013-11-16 11:43:38  [1505492.450715] tg3 0000:01:00.0: eth0: 0x00000860:
> 0xffffffff, 0xffffffff, 0xffffffff, 0x00000009
> 2013-11-16 11:43:38  [1505492.450716] tg3 0000:01:00.0: eth0: 0x00000880:
> 0x00000963, 0x019454f2, 0x00000000, 0x0000000a
> 2013-11-16 11:43:38  [1505492.450718] tg3 0000:01:00.0: eth0: 0x000008f0:
> 0x00000001, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450720] tg3 0000:01:00.0: eth0: 0x00000900:
> 0x00006c19, 0xffffffff, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450721] tg3 0000:01:00.0: eth0: 0x00000910:
> 0x00000000, 0xffffffff, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450723] tg3 0000:01:00.0: eth0: 0x00000920:
> 0x00000000, 0x00000000, 0xffffffff, 0x00000000
> 2013-11-16 11:43:38  [1505492.450725] tg3 0000:01:00.0: eth0: 0x00000930:
> 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff
> 2013-11-16 11:43:38  [1505492.450726] tg3 0000:01:00.0: eth0: 0x00000940:
> 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
> 2013-11-16 11:43:38  [1505492.450728] tg3 0000:01:00.0: eth0: 0x00000950:
> 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
> 2013-11-16 11:43:38  [1505492.450730] tg3 0000:01:00.0: eth0: 0x00000960:
> 0xffffffff, 0xffffffff, 0xffffffff, 0x00000071
> 2013-11-16 11:43:38  [1505492.450732] tg3 0000:01:00.0: eth0: 0x00000980:
> 0x00005e7f, 0x00000000, 0x00000000, 0x00000097
> 2013-11-16 11:43:38  [1505492.450733] tg3 0000:01:00.0: eth0: 0x00000990:
> 0x00000003, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450735] tg3 0000:01:00.0: eth0: 0x00000a00:
> 0xf428f606, 0x1613e7b3, 0x00000004, 0x00000000
> 2013-11-16 11:43:38  [1505492.450737] tg3 0000:01:00.0: eth0: 0x00000a20:
> 0x51b3edd8, 0x13a2f3e5, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450738] tg3 0000:01:00.0: eth0: 0x00000a40:
> 0x1bb17940, 0x1353913e, 0x00000002, 0x000000bb
> 2013-11-16 11:43:38  [1505492.450740] tg3 0000:01:00.0: eth0: 0x00000a60:
> 0xb79007bb, 0x13f86e55, 0x00000006, 0x00000000
> 2013-11-16 11:43:38  [1505492.450742] tg3 0000:01:00.0: eth0: 0x00000c00:
> 0x0000000a, 0x00000000, 0x00000003, 0x00000001
> 2013-11-16 11:43:38  [1505492.450743] tg3 0000:01:00.0: eth0: 0x00000c10:
> 0x00000000, 0x00000000, 0x00000000, 0x00f20000
> 2013-11-16 11:43:38  [1505492.450745] tg3 0000:01:00.0: eth0: 0x00000c80:
> 0x50438596, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450747] tg3 0000:01:00.0: eth0: 0x00000ce0:
> 0xf2cfb402, 0x0000000b, 0x000000f2, 0x00040028
> 2013-11-16 11:43:38  [1505492.450748] tg3 0000:01:00.0: eth0: 0x00000cf0:
> 0x00000000, 0x5000005f, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450750] tg3 0000:01:00.0: eth0: 0x00001000:
> 0x00000002, 0x00000000, 0xa000c4c6, 0x00000000
> 2013-11-16 11:43:38  [1505492.450752] tg3 0000:01:00.0: eth0: 0x00001010:
> 0x01df1df1, 0x0000c4c6, 0x00000000, 0x00000000
> 2013-11-16 11:43:38  [1505492.450754] tg3 0000:01:00.0: eth0: 0x00001400:
> 0x00000006, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450755] tg3 0000:01:00.0: eth0: 0x00001440:
> 0x000001df, 0x0000010d, 0x00000035, 0x000000bb
> 2013-11-16 11:43:39  [1505492.450757] tg3 0000:01:00.0: eth0: 0x00001480:
> 0x00002211, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450759] tg3 0000:01:00.0: eth0: 0x00001800:
> 0x00000036, 0x00000000, 0x000001df, 0x0000010d
> 2013-11-16 11:43:39  [1505492.450760] tg3 0000:01:00.0: eth0: 0x00001810:
> 0x00000035, 0x000000bb, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450762] tg3 0000:01:00.0: eth0: 0x00001830:
> 0x00000000, 0x00000000, 0x00000000, 0xf8354000
> 2013-11-16 11:43:39  [1505492.450764] tg3 0000:01:00.0: eth0: 0x00001840:
> 0xf82f8000, 0x00000017, 0x00000202, 0xc0000000
> 2013-11-16 11:43:39  [1505492.450766] tg3 0000:01:00.0: eth0: 0x00001850:
> 0x0000001f, 0x00000000, 0x000041e0, 0x010d01df
> 2013-11-16 11:43:39  [1505492.450767] tg3 0000:01:00.0: eth0: 0x00001860:
> 0x0100d200, 0x00000000, 0xf8355de0, 0x00000017
> 2013-11-16 11:43:39  [1505492.450769] tg3 0000:01:00.0: eth0: 0x00001c00:
> 0x00000002, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450771] tg3 0000:01:00.0: eth0: 0x00002000:
> 0x00000002, 0x00000010, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450773] tg3 0000:01:00.0: eth0: 0x00002010:
> 0x00000181, 0x00000001, 0x00780003, 0x00000000
> 2013-11-16 11:43:39  [1505492.450775] tg3 0000:01:00.0: eth0: 0x00002100:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450776] tg3 0000:01:00.0: eth0: 0x00002110:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450778] tg3 0000:01:00.0: eth0: 0x00002120:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450780] tg3 0000:01:00.0: eth0: 0x00002130:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450781] tg3 0000:01:00.0: eth0: 0x00002140:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450783] tg3 0000:01:00.0: eth0: 0x00002150:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450784] tg3 0000:01:00.0: eth0: 0x00002160:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450786] tg3 0000:01:00.0: eth0: 0x00002170:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450788] tg3 0000:01:00.0: eth0: 0x00002180:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450789] tg3 0000:01:00.0: eth0: 0x00002190:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450791] tg3 0000:01:00.0: eth0: 0x000021a0:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450793] tg3 0000:01:00.0: eth0: 0x000021b0:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450794] tg3 0000:01:00.0: eth0: 0x000021c0:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450796] tg3 0000:01:00.0: eth0: 0x000021d0:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450798] tg3 0000:01:00.0: eth0: 0x000021e0:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450799] tg3 0000:01:00.0: eth0: 0x000021f0:
> 0x000e1710, 0x000e1710, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450801] tg3 0000:01:00.0: eth0: 0x00002200:
> 0x3d943ab4, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450803] tg3 0000:01:00.0: eth0: 0x00002250:
> 0x00004e57, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450804] tg3 0000:01:00.0: eth0: 0x00002400:
> 0x00010012, 0x00000000, 0x00240001, 0x00000000
> 2013-11-16 11:43:39  [1505492.450806] tg3 0000:01:00.0: eth0: 0x00002410:
> 0x0000000f, 0x00005d00, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450808] tg3 0000:01:00.0: eth0: 0x00002440:
> 0x00000000, 0x00000000, 0x00000002, 0x00044400
> 2013-11-16 11:43:39  [1505492.450809] tg3 0000:01:00.0: eth0: 0x00002450:
> 0x00000017, 0xf6bb0000, 0x08001800, 0x00040000
> 2013-11-16 11:43:39  [1505492.450811] tg3 0000:01:00.0: eth0: 0x00002470:
> 0x00000000, 0x00000684, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450813] tg3 0000:01:00.0: eth0: 0x00002500:
> 0x00000000, 0x00000000, 0x00000002, 0x00044800
> 2013-11-16 11:43:39  [1505492.450815] tg3 0000:01:00.0: eth0: 0x00002510:
> 0x00000000, 0x00000000, 0x00000002, 0x00040400
> 2013-11-16 11:43:39  [1505492.450816] tg3 0000:01:00.0: eth0: 0x00002520:
> 0x00000000, 0x00000000, 0x00000002, 0x00044c00
> 2013-11-16 11:43:39  [1505492.450818] tg3 0000:01:00.0: eth0: 0x00002530:
> 0x00000000, 0x00000000, 0x00000002, 0x00040800
> 2013-11-16 11:43:39  [1505492.450819] tg3 0000:01:00.0: eth0: 0x00002540:
> 0x00000000, 0x00000000, 0x00000002, 0x00045000
> 2013-11-16 11:43:39  [1505492.450821] tg3 0000:01:00.0: eth0: 0x00002550:
> 0x00000000, 0x00000000, 0x00000002, 0x00040c00
> 2013-11-16 11:43:39  [1505492.450823] tg3 0000:01:00.0: eth0: 0x00002560:
> 0x00000000, 0x00000000, 0x00000002, 0x00045400
> 2013-11-16 11:43:39  [1505492.450824] tg3 0000:01:00.0: eth0: 0x00002570:
> 0x00000000, 0x00000000, 0x00000002, 0x00041000
> 2013-11-16 11:43:39  [1505492.450826] tg3 0000:01:00.0: eth0: 0x00002580:
> 0x00000000, 0x00000000, 0x00000002, 0x00045800
> 2013-11-16 11:43:39  [1505492.450828] tg3 0000:01:00.0: eth0: 0x00002590:
> 0x00000000, 0x00000000, 0x00000002, 0x00041400
> 2013-11-16 11:43:39  [1505492.450829] tg3 0000:01:00.0: eth0: 0x000025a0:
> 0x00000000, 0x00000000, 0x00000002, 0x00045c00
> 2013-11-16 11:43:39  [1505492.450831] tg3 0000:01:00.0: eth0: 0x000025b0:
> 0x00000000, 0x00000000, 0x00000002, 0x00041800
> 2013-11-16 11:43:39  [1505492.450833] tg3 0000:01:00.0: eth0: 0x000025c0:
> 0x00000000, 0x00000000, 0x00000002, 0x00046000
> 2013-11-16 11:43:39  [1505492.450834] tg3 0000:01:00.0: eth0: 0x000025d0:
> 0x00000000, 0x00000000, 0x00000002, 0x00041c00
> 2013-11-16 11:43:39  [1505492.450836] tg3 0000:01:00.0: eth0: 0x000025e0:
> 0x00000000, 0x00000000, 0x00000002, 0x00046400
> 2013-11-16 11:43:39  [1505492.450838] tg3 0000:01:00.0: eth0: 0x000025f0:
> 0x00000000, 0x00000000, 0x00000002, 0x00042000
> 2013-11-16 11:43:39  [1505492.450839] tg3 0000:01:00.0: eth0: 0x00002600:
> 0x00000000, 0x00000000, 0x00000002, 0x00046800
> 2013-11-16 11:43:39  [1505492.450841] tg3 0000:01:00.0: eth0: 0x00002610:
> 0x00000000, 0x00000000, 0x00000002, 0x00042400
> 2013-11-16 11:43:39  [1505492.450843] tg3 0000:01:00.0: eth0: 0x00002620:
> 0x00000000, 0x00000000, 0x00000002, 0x00046c00
> 2013-11-16 11:43:39  [1505492.450844] tg3 0000:01:00.0: eth0: 0x00002630:
> 0x00000000, 0x00000000, 0x00000002, 0x00042800
> 2013-11-16 11:43:39  [1505492.450846] tg3 0000:01:00.0: eth0: 0x00002640:
> 0x00000000, 0x00000000, 0x00000002, 0x00047000
> 2013-11-16 11:43:39  [1505492.450848] tg3 0000:01:00.0: eth0: 0x00002650:
> 0x00000000, 0x00000000, 0x00000002, 0x00042c00
> 2013-11-16 11:43:39  [1505492.450849] tg3 0000:01:00.0: eth0: 0x00002660:
> 0x00000000, 0x00000000, 0x00000002, 0x00047400
> 2013-11-16 11:43:39  [1505492.450851] tg3 0000:01:00.0: eth0: 0x00002670:
> 0x00000000, 0x00000000, 0x00000002, 0x00043000
> 2013-11-16 11:43:39  [1505492.450852] tg3 0000:01:00.0: eth0: 0x00002680:
> 0x00000000, 0x00000000, 0x00000002, 0x00047800
> 2013-11-16 11:43:39  [1505492.450854] tg3 0000:01:00.0: eth0: 0x00002690:
> 0x00000000, 0x00000000, 0x00000002, 0x00043400
> 2013-11-16 11:43:39  [1505492.450856] tg3 0000:01:00.0: eth0: 0x000026a0:
> 0x00000000, 0x00000000, 0x00000002, 0x00047c00
> 2013-11-16 11:43:39  [1505492.450857] tg3 0000:01:00.0: eth0: 0x000026b0:
> 0x00000000, 0x00000000, 0x00000002, 0x00043800
> 2013-11-16 11:43:39  [1505492.450859] tg3 0000:01:00.0: eth0: 0x000026c0:
> 0x00000000, 0x00000000, 0x00000002, 0x00048000
> 2013-11-16 11:43:39  [1505492.450861] tg3 0000:01:00.0: eth0: 0x000026d0:
> 0x00000000, 0x00000000, 0x00000002, 0x00043c00
> 2013-11-16 11:43:39  [1505492.450862] tg3 0000:01:00.0: eth0: 0x000026e0:
> 0x00000000, 0x00000000, 0x00000002, 0x00048400
> 2013-11-16 11:43:39  [1505492.450864] tg3 0000:01:00.0: eth0: 0x000026f0:
> 0x00000000, 0x00000000, 0x00000002, 0x00044000
> 2013-11-16 11:43:39  [1505492.450866] tg3 0000:01:00.0: eth0: 0x00002800:
> 0x00000006, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450868] tg3 0000:01:00.0: eth0: 0x00002c00:
> 0x00000006, 0x00000000, 0x00000000, 0x00000699
> 2013-11-16 11:43:39  [1505492.450869] tg3 0000:01:00.0: eth0: 0x00002c10:
> 0x00000000, 0x00000000, 0x00000019, 0x0000000c
> 2013-11-16 11:43:39  [1505492.450871] tg3 0000:01:00.0: eth0: 0x00002c20:
> 0x00000002, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450873] tg3 0000:01:00.0: eth0: 0x00002d00:
> 0x00000080, 0x00000040, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450874] tg3 0000:01:00.0: eth0: 0x00003000:
> 0x00000006, 0x00000000, 0x00000000, 0x00000699
> 2013-11-16 11:43:39  [1505492.450876] tg3 0000:01:00.0: eth0: 0x00003400:
> 0x00000004, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450878] tg3 0000:01:00.0: eth0: 0x00003600:
> 0x00004600, 0x00170000, 0x00110000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450880] tg3 0000:01:00.0: eth0: 0x00003610:
> 0x00170000, 0x00000000, 0x00130000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450881] tg3 0000:01:00.0: eth0: 0x00003620:
> 0x00110011, 0x00000000, 0x00000000, 0x00032080
> 2013-11-16 11:43:39  [1505492.450883] tg3 0000:01:00.0: eth0: 0x00003630:
> 0x00800000, 0x87748774, 0x02c01000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450885] tg3 0000:01:00.0: eth0: 0x00003640:
> 0x00000000, 0x00000000, 0x00000020, 0x00000019
> 2013-11-16 11:43:39  [1505492.450886] tg3 0000:01:00.0: eth0: 0x00003650:
> 0x00000171, 0x000f03ff, 0x05720000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450888] tg3 0000:01:00.0: eth0: 0x00003660:
> 0x00000000, 0x00000000, 0x02000000, 0x00000202
> 2013-11-16 11:43:39  [1505492.450890] tg3 0000:01:00.0: eth0: 0x00003670:
> 0x00000000, 0xfeffffe3, 0x00000000, 0x00000020
> 2013-11-16 11:43:39  [1505492.450891] tg3 0000:01:00.0: eth0: 0x00003680:
> 0x30018010, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450893] tg3 0000:01:00.0: eth0: 0x000036a0:
> 0x000001a0, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450895] tg3 0000:01:00.0: eth0: 0x000036b0:
> 0x0010034c, 0x07ff07ff, 0x07ff07ff, 0x01000004
> 2013-11-16 11:43:39  [1505492.450896] tg3 0000:01:00.0: eth0: 0x000036c0:
> 0xffffffff, 0x00000000, 0x00000000, 0x8c58c9dc
> 2013-11-16 11:43:39  [1505492.450898] tg3 0000:01:00.0: eth0: 0x000036d0:
> 0x0000019d, 0x00000000, 0x00000000, 0x000048ef
> 2013-11-16 11:43:39  [1505492.450900] tg3 0000:01:00.0: eth0: 0x000036f0:
> 0x00000000, 0x00000000, 0x00000000, 0x00010801
> 2013-11-16 11:43:39  [1505492.450902] tg3 0000:01:00.0: eth0: 0x00003800:
> 0x00000001, 0x00000000, 0x0000000e, 0x0516028b
> 2013-11-16 11:43:39  [1505492.450903] tg3 0000:01:00.0: eth0: 0x00003810:
> 0x0000002f, 0x000000ba, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450905] tg3 0000:01:00.0: eth0: 0x00003c00:
> 0x00000306, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450907] tg3 0000:01:00.0: eth0: 0x00003c30:
> 0x00000000, 0x00000000, 0x00000017, 0xfa561000
> 2013-11-16 11:43:39  [1505492.450908] tg3 0000:01:00.0: eth0: 0x00003c40:
> 0x00000000, 0x00000b00, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450910] tg3 0000:01:00.0: eth0: 0x00003c50:
> 0x00000000, 0x00000699, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450912] tg3 0000:01:00.0: eth0: 0x00003c80:
> 0x000001d6, 0x00000d76, 0x000004e6, 0x00000267
> 2013-11-16 11:43:39  [1505492.450913] tg3 0000:01:00.0: eth0: 0x00003cc0:
> 0x000001ea, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450915] tg3 0000:01:00.0: eth0: 0x00003cd0:
> 0x00000000, 0x0000000f, 0x00000000, 0x00000000
> 2013-11-16 11:43:39  [1505492.450917] tg3 0000:01:00.0: eth0: 0x00003d00:
> 0x00000017, 0xf7fe1000, 0x00000017, 0xf73b8000
> 2013-11-16 11:43:39  [1505492.450918] tg3 0000:01:00.0: eth0: 0x00003d10:
> 0x00000017, 0xf7079000, 0x00000017, 0xf900c000
> 2013-11-16 11:43:39  [1505492.450920] tg3 0000:01:00.0: eth0: 0x00003d80:
> 0x00000014, 0x00000048, 0x00000005, 0x00000035
> 2013-11-16 11:43:39  [1505492.450922] tg3 0000:01:00.0: eth0: 0x00003d90:
> 0x00000005, 0x00000005, 0x00000014, 0x00000048
> 2013-11-16 11:43:39  [1505492.450924] tg3 0000:01:00.0: eth0: 0x00003da0:
> 0x00000005, 0x00000035, 0x00000005, 0x00000005
> 2013-11-16 11:43:40  [1505492.450925] tg3 0000:01:00.0: eth0: 0x00003db0:
> 0x00000014, 0x00000048, 0x00000005, 0x00000035
> 2013-11-16 11:43:40  [1505492.450927] tg3 0000:01:00.0: eth0: 0x00003dc0:
> 0x00000005, 0x00000005, 0x00000014, 0x00000048
> 2013-11-16 11:43:40  [1505492.450929] tg3 0000:01:00.0: eth0: 0x00003dd0:
> 0x00000005, 0x00000035, 0x00000005, 0x00000005
> 2013-11-16 11:43:40  [1505492.450930] tg3 0000:01:00.0: eth0: 0x00003f00:
> 0x00000000, 0x0000010d, 0x00000035, 0x000000bb
> 2013-11-16 11:43:40  [1505492.450932] tg3 0000:01:00.0: eth0: 0x00003fc0:
> 0x001e87b9, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.450934] tg3 0000:01:00.0: eth0: 0x00004000:
> 0x00000002, 0x00000000, 0x0012140b, 0x00143a42
> 2013-11-16 11:43:40  [1505492.450936] tg3 0000:01:00.0: eth0: 0x00004010:
> 0x00000000, 0x00201012, 0x00000490, 0x02005422
> 2013-11-16 11:43:40  [1505492.450937] tg3 0000:01:00.0: eth0: 0x00004020:
> 0x00000000, 0x00000000, 0x00000010, 0x00000000
> 2013-11-16 11:43:40  [1505492.450939] tg3 0000:01:00.0: eth0: 0x00004030:
> 0x00000010, 0x00806510, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.450940] tg3 0000:01:00.0: eth0: 0x00004040:
> 0x00000000, 0x00000000, 0x01085220, 0x00000000
> 2013-11-16 11:43:40  [1505492.450942] tg3 0000:01:00.0: eth0: 0x00004050:
> 0x00000000, 0x00000000, 0x0033a010, 0x004d7002
> 2013-11-16 11:43:40  [1505492.450944] tg3 0000:01:00.0: eth0: 0x00004060:
> 0x004e3000, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.450946] tg3 0000:01:00.0: eth0: 0x00004400:
> 0x00000016, 0x00000000, 0x00010000, 0x0000a000
> 2013-11-16 11:43:40  [1505492.450947] tg3 0000:01:00.0: eth0: 0x00004410:
> 0x00000000, 0x0000002a, 0x000000a0, 0x00000000
> 2013-11-16 11:43:40  [1505492.450949] tg3 0000:01:00.0: eth0: 0x00004420:
> 0x0000003d, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.450951] tg3 0000:01:00.0: eth0: 0x00004440:
> 0x00000000, 0x00000000, 0x00000000, 0x00000804
> 2013-11-16 11:43:40  [1505492.450952] tg3 0000:01:00.0: eth0: 0x00004450:
> 0x00100538, 0x013b0003, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.450954] tg3 0000:01:00.0: eth0: 0x00004800:
> 0x380303fe, 0x00000000, 0x00000000, 0x00000120
> 2013-11-16 11:43:40  [1505492.450956] tg3 0000:01:00.0: eth0: 0x00004810:
> 0x00000000, 0x0000000a, 0x00689c74, 0x00001514
> 2013-11-16 11:43:40  [1505492.450958] tg3 0000:01:00.0: eth0: 0x00004820:
> 0x000000e3, 0x00000000, 0xf0330000, 0x22ee9ae8
> 2013-11-16 11:43:40  [1505492.450959] tg3 0000:01:00.0: eth0: 0x00004830:
> 0x00000000, 0x000002b4, 0x000002b4, 0x00000000
> 2013-11-16 11:43:40  [1505492.450961] tg3 0000:01:00.0: eth0: 0x00004840:
> 0x00e18278, 0x00e18278, 0x000e2200, 0xe3426024
> 2013-11-16 11:43:40  [1505492.450963] tg3 0000:01:00.0: eth0: 0x00004850:
> 0x21cb6453, 0x702305ea, 0xd7d6d7d6, 0x00000000
> 2013-11-16 11:43:40  [1505492.450964] tg3 0000:01:00.0: eth0: 0x00004860:
> 0x000000e3, 0x11283020, 0x00100800, 0xf3000008
> 2013-11-16 11:43:40  [1505492.450966] tg3 0000:01:00.0: eth0: 0x00004870:
> 0x05ea0080, 0x003e1820, 0x003e1820, 0x00000000
> 2013-11-16 11:43:40  [1505492.450968] tg3 0000:01:00.0: eth0: 0x00004880:
> 0x0000e0db, 0x551fe086, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.450970] tg3 0000:01:00.0: eth0: 0x00004900:
> 0x28190404, 0x00305407, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.450971] tg3 0000:01:00.0: eth0: 0x00004910:
> 0x000f001c, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.450973] tg3 0000:01:00.0: eth0: 0x00004a00:
> 0x180303fe, 0x00100000, 0x00100010, 0x963b0000
> 2013-11-16 11:43:40  [1505492.450975] tg3 0000:01:00.0: eth0: 0x00004a10:
> 0xf8355e60, 0x008ca924, 0x00100012, 0x00000000
> 2013-11-16 11:43:40  [1505492.450976] tg3 0000:01:00.0: eth0: 0x00004a20:
> 0x00000000, 0x00000010, 0xf02c0000, 0xf8355ea0
> 2013-11-16 11:43:40  [1505492.450978] tg3 0000:01:00.0: eth0: 0x00004a30:
> 0x00000000, 0x00000032, 0x00000032, 0x00000000
> 2013-11-16 11:43:40  [1505492.450980] tg3 0000:01:00.0: eth0: 0x00004a40:
> 0xf8355e50, 0xf8355e60, 0xf8355e70, 0xf8355e40
> 2013-11-16 11:43:40  [1505492.450981] tg3 0000:01:00.0: eth0: 0x00004a50:
> 0x00100010, 0x00100010, 0x00100010, 0x00100010
> 2013-11-16 11:43:40  [1505492.450983] tg3 0000:01:00.0: eth0: 0x00004a70:
> 0x28190404, 0x00305407, 0x000f001c, 0x00000000
> 2013-11-16 11:43:40  [1505492.450985] tg3 0000:01:00.0: eth0: 0x00004b00:
> 0x180303fe, 0x00f30003, 0x30000000, 0x00f30120
> 2013-11-16 11:43:40  [1505492.450987] tg3 0000:01:00.0: eth0: 0x00004b10:
> 0x00f20040, 0x00f00003, 0x00f3dc78, 0x00000010
> 2013-11-16 11:43:40  [1505492.450988] tg3 0000:01:00.0: eth0: 0x00004b20:
> 0x00000003, 0x02000000, 0xd6aa1001, 0x0ff300f8
> 2013-11-16 11:43:40  [1505492.450990] tg3 0000:01:00.0: eth0: 0x00004b30:
> 0xd6aa1401, 0x0ff300f8, 0xd6aa0801, 0x0ff200f8
> 2013-11-16 11:43:40  [1505492.450992] tg3 0000:01:00.0: eth0: 0x00004b40:
> 0xd6aa0c01, 0x0ff000f8, 0x0101d7d7, 0x60603535
> 2013-11-16 11:43:40  [1505492.450994] tg3 0000:01:00.0: eth0: 0x00004b50:
> 0xf0330000, 0xd6aa10f8, 0xaf100000, 0x03000002
> 2013-11-16 11:43:40  [1505492.450996] tg3 0000:01:00.0: eth0: 0x00004b60:
> 0xf0330000, 0xd6aa14f8, 0xaf100000, 0x400001ea
> 2013-11-16 11:43:40  [1505492.450997] tg3 0000:01:00.0: eth0: 0x00004b70:
> 0xf0330000, 0xd6aa08f8, 0xaf100000, 0x000000ff
> 2013-11-16 11:43:40  [1505492.450999] tg3 0000:01:00.0: eth0: 0x00004b80:
> 0x00000003, 0x11283020, 0x00100800, 0xf3000008
> 2013-11-16 11:43:40  [1505492.451001] tg3 0000:01:00.0: eth0: 0x00004b90:
> 0x05ea0080, 0x28190404, 0x00305407, 0x000f001c
> 2013-11-16 11:43:40  [1505492.451003] tg3 0000:01:00.0: eth0: 0x00004ba0:
> 0x00f00092, 0x00000003, 0x11283020, 0x000f001c
> 2013-11-16 11:43:40  [1505492.451004] tg3 0000:01:00.0: eth0: 0x00004bb0:
> 0xd6aa0001, 0xd6aa0401, 0xf2cfd001, 0xf2cfb401
> 2013-11-16 11:43:40  [1505492.451006] tg3 0000:01:00.0: eth0: 0x00004bc0:
> 0xd6aa1002, 0xd6aa1402, 0xd6aa0802, 0xd6aa0c02
> 2013-11-16 11:43:40  [1505492.451008] tg3 0000:01:00.0: eth0: 0x00004bd0:
> 0xd6aa0002, 0xd6aa0402, 0xf2cfd002, 0xf2cfb402
> 2013-11-16 11:43:40  [1505492.451009] tg3 0000:01:00.0: eth0: 0x00004be0:
> 0x00f300f3, 0x00f000f2, 0x00f300f2, 0x00f000f1
> 2013-11-16 11:43:40  [1505492.451011] tg3 0000:01:00.0: eth0: 0x00004bf0:
> 0xf0330000, 0xd6aa0cf8, 0xaf0f0000, 0x0000ffff
> 2013-11-16 11:43:40  [1505492.451013] tg3 0000:01:00.0: eth0: 0x00004c00:
> 0x200003fe, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451014] tg3 0000:01:00.0: eth0: 0x00004c10:
> 0x0000003f, 0x00000000, 0x00000006, 0x00000000
> 2013-11-16 11:43:40  [1505492.451016] tg3 0000:01:00.0: eth0: 0x00004c20:
> 0x00000000, 0x00000000, 0x00000000, 0x00000006
> 2013-11-16 11:43:40  [1505492.451018] tg3 0000:01:00.0: eth0: 0x00004c30:
> 0x00000000, 0x035d8000, 0x00108000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451020] tg3 0000:01:00.0: eth0: 0x00004c40:
> 0x00000020, 0x00000000, 0x001d0020, 0x00140020
> 2013-11-16 11:43:40  [1505492.451021] tg3 0000:01:00.0: eth0: 0x00004c50:
> 0xe5d751d5, 0x001d5266, 0x674e6d76, 0x63193f3f
> 2013-11-16 11:43:40  [1505492.451023] tg3 0000:01:00.0: eth0: 0x00004c60:
> 0x00000020, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451025] tg3 0000:01:00.0: eth0: 0x00005000:
> 0x00009800, 0x80004000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451026] tg3 0000:01:00.0: eth0: 0x00005010:
> 0x00000000, 0x00000000, 0x00000000, 0x08001fc0
> 2013-11-16 11:43:40  [1505492.451028] tg3 0000:01:00.0: eth0: 0x00005020:
> 0x00021f02, 0x00000000, 0x00000000, 0x40000020
> 2013-11-16 11:43:40  [1505492.451030] tg3 0000:01:00.0: eth0: 0x00005030:
> 0x00000000, 0x0000001d, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451031] tg3 0000:01:00.0: eth0: 0x00005040:
> 0x00000000, 0x00000000, 0x080019d2, 0x00000000
> 2013-11-16 11:43:40  [1505492.451033] tg3 0000:01:00.0: eth0: 0x00005080:
> 0x00009800, 0x80004000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451035] tg3 0000:01:00.0: eth0: 0x00005090:
> 0x00000000, 0x00000000, 0x00000000, 0x0800185c
> 2013-11-16 11:43:40  [1505492.451036] tg3 0000:01:00.0: eth0: 0x000050a0:
> 0xafa40014, 0x00000000, 0x00000000, 0x40000020
> 2013-11-16 11:43:40  [1505492.451038] tg3 0000:01:00.0: eth0: 0x000050b0:
> 0x00000000, 0x0000001d, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451040] tg3 0000:01:00.0: eth0: 0x000050c0:
> 0x00000000, 0x00000000, 0x08000088, 0x00000000
> 2013-11-16 11:43:40  [1505492.451042] tg3 0000:01:00.0: eth0: 0x00005100:
> 0x00009800, 0x80000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451043] tg3 0000:01:00.0: eth0: 0x00005110:
> 0x00000000, 0x00000000, 0x00000000, 0x08002ca0
> 2013-11-16 11:43:40  [1505492.451045] tg3 0000:01:00.0: eth0: 0x00005120:
> 0x30420001, 0x00000000, 0x00000000, 0x40000020
> 2013-11-16 11:43:40  [1505492.451047] tg3 0000:01:00.0: eth0: 0x00005130:
> 0x00000000, 0x0000001d, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451048] tg3 0000:01:00.0: eth0: 0x00005140:
> 0x00000000, 0x00000000, 0x0800203c, 0x00000000
> 2013-11-16 11:43:40  [1505492.451050] tg3 0000:01:00.0: eth0: 0x00005180:
> 0x00009800, 0x80004000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451052] tg3 0000:01:00.0: eth0: 0x00005190:
> 0x00000000, 0x00000000, 0x00000000, 0x08001fac
> 2013-11-16 11:43:40  [1505492.451053] tg3 0000:01:00.0: eth0: 0x000051a0:
> 0x2404000f, 0x00000000, 0x00000000, 0x40000020
> 2013-11-16 11:43:40  [1505492.451055] tg3 0000:01:00.0: eth0: 0x000051b0:
> 0x00000000, 0x0000001d, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451057] tg3 0000:01:00.0: eth0: 0x000051c0:
> 0x00000000, 0x00000000, 0x080019d2, 0x00000000
> 2013-11-16 11:43:40  [1505492.451058] tg3 0000:01:00.0: eth0: 0x00005200:
> 0x00000000, 0x0b9604fa, 0x06000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451060] tg3 0000:01:00.0: eth0: 0x00005210:
> 0xc0000000, 0xc0000000, 0x00000000, 0x0b9604fa
> 2013-11-16 11:43:40  [1505492.451062] tg3 0000:01:00.0: eth0: 0x00005220:
> 0x06000000, 0x00000000, 0x00000000, 0xc0000000
> 2013-11-16 11:43:40  [1505492.451064] tg3 0000:01:00.0: eth0: 0x00005230:
> 0x00000000, 0x0b9604fa, 0x06000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451066] tg3 0000:01:00.0: eth0: 0x00005240:
> 0x00000000, 0x00000000, 0x00000000, 0x0b9604fa
> 2013-11-16 11:43:40  [1505492.451067] tg3 0000:01:00.0: eth0: 0x00005250:
> 0x06000000, 0x00000000, 0xc0000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451069] tg3 0000:01:00.0: eth0: 0x00005260:
> 0x00000000, 0x0b9604fa, 0x06000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451071] tg3 0000:01:00.0: eth0: 0x00005270:
> 0xc0000000, 0xc0000000, 0x00000000, 0x0b9604fa
> 2013-11-16 11:43:40  [1505492.451073] tg3 0000:01:00.0: eth0: 0x00005280:
> 0x00009800, 0x80000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451074] tg3 0000:01:00.0: eth0: 0x00005290:
> 0x00000000, 0x00000000, 0x00000000, 0x08002ca0
> 2013-11-16 11:43:40  [1505492.451076] tg3 0000:01:00.0: eth0: 0x000052a0:
> 0x30420001, 0x00000000, 0x00000000, 0x40000020
> 2013-11-16 11:43:40  [1505492.451078] tg3 0000:01:00.0: eth0: 0x000052b0:
> 0x00000000, 0x0000001d, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451079] tg3 0000:01:00.0: eth0: 0x000052c0:
> 0x00000000, 0x00000000, 0x0800203c, 0x00000000
> 2013-11-16 11:43:40  [1505492.451081] tg3 0000:01:00.0: eth0: 0x00005300:
> 0x00009800, 0x80004000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451083] tg3 0000:01:00.0: eth0: 0x00005310:
> 0x00000000, 0x00000000, 0x00000000, 0x08001fac
> 2013-11-16 11:43:40  [1505492.451084] tg3 0000:01:00.0: eth0: 0x00005320:
> 0x2404000f, 0x00000000, 0x00000000, 0x40000020
> 2013-11-16 11:43:40  [1505492.451086] tg3 0000:01:00.0: eth0: 0x00005330:
> 0x00000000, 0x0000001d, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451088] tg3 0000:01:00.0: eth0: 0x00005340:
> 0x00000000, 0x00000000, 0x080019d2, 0x00000000
> 2013-11-16 11:43:40  [1505492.451089] tg3 0000:01:00.0: eth0: 0x00005380:
> 0x00009800, 0x80004000, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451091] tg3 0000:01:00.0: eth0: 0x00005390:
> 0x00000000, 0x00000000, 0x00000000, 0x0800185c
> 2013-11-16 11:43:40  [1505492.451093] tg3 0000:01:00.0: eth0: 0x000053a0:
> 0xafa40014, 0x00000000, 0x00000000, 0x40000020
> 2013-11-16 11:43:40  [1505492.451094] tg3 0000:01:00.0: eth0: 0x000053b0:
> 0x00000000, 0x0000001d, 0x00000000, 0x00000000
> 2013-11-16 11:43:40  [1505492.451096] tg3 0000:01:00.0: eth0: 0x000053c0:
> 0x00000000, 0x00000000, 0x08000088, 0x00000000
> 2013-11-16 11:43:41  [1505492.451098] tg3 0000:01:00.0: eth0: 0x00005800:
> 0x3f000000, 0x3f000000, 0x00000001, 0x00000000
> 2013-11-16 11:43:41  [1505492.451099] tg3 0000:01:00.0: eth0: 0x00005810:
> 0x10000000, 0x00000000, 0xae000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451101] tg3 0000:01:00.0: eth0: 0x00005820:
> 0x00000001, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451103] tg3 0000:01:00.0: eth0: 0x00005860:
> 0x00000000, 0x00000000, 0x000006a1, 0x000006a1
> 2013-11-16 11:43:41  [1505492.451104] tg3 0000:01:00.0: eth0: 0x00005880:
> 0x000001d2, 0x000001d2, 0x00000d76, 0x00000d76
> 2013-11-16 11:43:41  [1505492.451106] tg3 0000:01:00.0: eth0: 0x00005890:
> 0x000004e6, 0x000004e6, 0x000001b5, 0x000001b5
> 2013-11-16 11:43:41  [1505492.451108] tg3 0000:01:00.0: eth0: 0x00005900:
> 0x000001ea, 0x000001ea, 0x0000010d, 0x00000035
> 2013-11-16 11:43:41  [1505492.451110] tg3 0000:01:00.0: eth0: 0x00005910:
> 0x000000bb, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451111] tg3 0000:01:00.0: eth0: 0x00005980:
> 0x000001ea, 0x0000010d, 0x00000035, 0x000000bb
> 2013-11-16 11:43:41  [1505492.451113] tg3 0000:01:00.0: eth0: 0x00005a00:
> 0x000f601f, 0x00000000, 0x00010000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451115] tg3 0000:01:00.0: eth0: 0x00006000:
> 0x00010082, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451117] tg3 0000:01:00.0: eth0: 0x00006400:
> 0x00000000, 0x00000000, 0x00010891, 0xc0000000
> 2013-11-16 11:43:41  [1505492.451118] tg3 0000:01:00.0: eth0: 0x00006410:
> 0x0a000064, 0x0a000064, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451120] tg3 0000:01:00.0: eth0: 0x00006420:
> 0x00000000, 0x00000000, 0x00000000, 0x818c0000
> 2013-11-16 11:43:41  [1505492.451122] tg3 0000:01:00.0: eth0: 0x00006430:
> 0x78000000, 0x14e4165f, 0x1f5b1028, 0x00020000
> 2013-11-16 11:43:41  [1505492.451123] tg3 0000:01:00.0: eth0: 0x00006440:
> 0x0000304f, 0x000002e4, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451125] tg3 0000:01:00.0: eth0: 0x000064c0:
> 0x00000010, 0x00000004, 0x00001004, 0x00000000
> 2013-11-16 11:43:41  [1505492.451127] tg3 0000:01:00.0: eth0: 0x000064d0:
> 0x00000000, 0x10008d81, 0x00000000, 0x00315e22
> 2013-11-16 11:43:41  [1505492.451129] tg3 0000:01:00.0: eth0: 0x000064e0:
> 0x00000031, 0x0000001f, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451130] tg3 0000:01:00.0: eth0: 0x000064f0:
> 0x00000002, 0x00000031, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451132] tg3 0000:01:00.0: eth0: 0x00006500:
> 0x01e10003, 0x1c3f67fa, 0x000090b1, 0x00000003
> 2013-11-16 11:43:41  [1505492.451134] tg3 0000:01:00.0: eth0: 0x00006510:
> 0x0007811b, 0x00058116, 0x00046113, 0x00000000
> 2013-11-16 11:43:41  [1505492.451136] tg3 0000:01:00.0: eth0: 0x00006550:
> 0x00000001, 0x02800000, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451138] tg3 0000:01:00.0: eth0: 0x000065f0:
> 0x00000000, 0x00000109, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451139] tg3 0000:01:00.0: eth0: 0x00006800:
> 0x14130034, 0x20099082, 0x01029208, 0xfade98a5
> 2013-11-16 11:43:41  [1505492.451141] tg3 0000:01:00.0: eth0: 0x00006810:
> 0x21020000, 0xffffffff, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451143] tg3 0000:01:00.0: eth0: 0x00006830:
> 0xffffffff, 0xffffffff, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451144] tg3 0000:01:00.0: eth0: 0x00006840:
> 0x00000000, 0x00000001, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451146] tg3 0000:01:00.0: eth0: 0x00006890:
> 0x00000000, 0x88003800, 0x00000000, 0x04102040
> 2013-11-16 11:43:41  [1505492.451148] tg3 0000:01:00.0: eth0: 0x000068a0:
> 0x00000020, 0x00000001, 0x03ff03ff, 0x00000000
> 2013-11-16 11:43:41  [1505492.451149] tg3 0000:01:00.0: eth0: 0x000068b0:
> 0xe0011514, 0x00000000, 0x00000000, 0x00000000
> 2013-11-16 11:43:41  [1505492.451151] tg3 0000:01:00.0: eth0: 0x000068e0:
> 0x00000000, 0x00000000, 0x00000000, 0x00050b08
> 2013-11-16 11:43:41  [1505492.451153] tg3 0000:01:00.0: eth0: 0x000068f0:
> 0x00ff000e, 0x00ff0000, 0x00000000, 0x04444444
> 2013-11-16 11:43:41  [1505492.451154] tg3 0000:01:00.0: eth0: 0x00006920:
> 0x00000000, 0x00000000, 0x00000001, 0x00000000
> 2013-11-16 11:43:41  [1505492.451156] tg3 0000:01:00.0: eth0: 0x00007000:
> 0x00000008, 0x00000000, 0x00000000, 0x00004868
> 2013-11-16 11:43:41  [1505492.451158] tg3 0000:01:00.0: eth0: 0x00007010:
> 0x1a5876c2, 0x01c08073, 0x00d70081, 0x03008200
> 2013-11-16 11:43:41  [1505492.451160] tg3 0000:01:00.0: eth0: 0x00007020:
> 0x00000000, 0x00000000, 0x00000406, 0x10004000
> 2013-11-16 11:43:41  [1505492.451161] tg3 0000:01:00.0: eth0: 0x00007030:
> 0x000e0000, 0x0000486c, 0x00170030, 0x00000000
> 2013-11-16 11:43:41  [1505492.451165] tg3 0000:01:00.0: eth0: 0: Host status
> block [00000004:0000003f:(0000:02e5:0000):(0000:0000)]
> 2013-11-16 11:43:41  [1505492.451167] tg3 0000:01:00.0: eth0: 0: NAPI info
> [0000003f:0000003f:(0000:0000:01ff):0000:(06a1:0000:0000:0000)]
> 2013-11-16 11:43:41  [1505492.451169] tg3 0000:01:00.0: eth0: 1: Host status
> block [00000001:00000033:(0000:0000:0000):(01d6:0013)]
> 2013-11-16 11:43:41  [1505492.451171] tg3 0000:01:00.0: eth0: 1: NAPI info
> [000000fb:000000fb:(0013:01df:01ff):01d2:(01d2:01d2:0000:0000)]
> 2013-11-16 11:43:41  [1505492.451173] tg3 0000:01:00.0: eth0: 2: Host status
> block [00000001:00000010:(0d76:0000:0000):(0000:010d)]
> 2013-11-16 11:43:41  [1505492.451176] tg3 0000:01:00.0: eth0: 2: NAPI info
> [00000010:00000010:(010d:010d:01ff):0d76:(0576:0573:0000:0000)]
> 2013-11-16 11:43:41  [1505492.451178] tg3 0000:01:00.0: eth0: 3: Host status
> block [00000001:000000ae:(0000:0000:0000):(0000:0035)]
> 2013-11-16 11:43:41  [1505492.451180] tg3 0000:01:00.0: eth0: 3: NAPI info
> [000000ae:000000ae:(0035:0035:01ff):04e6:(04e6:04df:0000:0000)]
> 2013-11-16 11:43:41  [1505492.451182] tg3 0000:01:00.0: eth0: 4: Host status
> block [00000001:000000b2:(0000:0000:0267):(0000:00bb)]
> 2013-11-16 11:43:41  [1505492.451184] tg3 0000:01:00.0: eth0: 4: NAPI info
> [000000cd:000000cd:(00bb:0062:01ff):01b5:(01b5:01b5:0000:0000)]
> 2013-11-16 11:43:41  [1505492.457748] tg3 0000:01:00.0: eth0: The system may
> be re-ordering memory-mapped I/O cycles to the network device, attempting to
> recover. Please report the problem to the driver maintainer and include
> system chipset information.
> 2013-11-16 11:43:41  [1505492.490118] tg3 0000:01:00.0: eth0: Link is down
> 2013-11-16 11:43:41  [1505498.044676] tg3 0000:01:00.0: eth0: Link is up at
> 1000 Mbps, full duplex
> 2013-11-16 11:43:41  [1505498.044678] tg3 0000:01:00.0: eth0: Flow control
> is off for TX and off for RX
> 2013-11-16 11:43:41  [1505498.044680] tg3 0000:01:00.0: eth0: EEE is
> disabled
>
> Further information:
> Current output of "ethtool -k eth0":
> rx-checksumming: on
> tx-checksumming: on
>         tx-checksum-ipv4: on
>         tx-checksum-ip-generic: off [fixed]
>         tx-checksum-ipv6: on
>         tx-checksum-fcoe-crc: off [fixed]
>         tx-checksum-sctp: off [fixed]
> scatter-gather: on
>         tx-scatter-gather: on
>         tx-scatter-gather-fraglist: off [fixed]
> tcp-segmentation-offload: off
>         tx-tcp-segmentation: off
>         tx-tcp-ecn-segmentation: off
>         tx-tcp6-segmentation: off
> udp-fragmentation-offload: off [fixed]
> generic-segmentation-offload: on
> generic-receive-offload: on
> large-receive-offload: off [fixed]
> rx-vlan-offload: on
> tx-vlan-offload: on
> ntuple-filters: off [fixed]
> receive-hashing: off [fixed]
> highdma: on
> rx-vlan-filter: off [fixed]
> vlan-challenged: off [fixed]
> tx-lockless: off [fixed]
> netns-local: off [fixed]
> tx-gso-robust: off [fixed]
> tx-fcoe-segmentation: off [fixed]
> fcoe-mtu: off [fixed]
> tx-nocache-copy: on
> loopback: off [fixed]
> rx-fcs: off [fixed]
> rx-all: off [fixed]
>
> Current output of "lscpi -vvvv" for eth0:
> 01:00.1 Ethernet controller: Broadcom Corporation NetXtreme BCM5720 Gigabit
> Ethernet PCIe
>         Subsystem: Dell Device 1f5b
>         Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping- SERR- FastB2B- DisINTx+
>         Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
> <TAbort- <MAbort- >SERR- <PERR- INTx-
>         Latency: 0, Cache Line Size: 64 bytes
>         Interrupt: pin B routed to IRQ 38
>         Region 0: Memory at d57d0000 (64-bit, prefetchable) [size=64K]
>         Region 2: Memory at d57e0000 (64-bit, prefetchable) [size=64K]
>         Region 4: Memory at d57f0000 (64-bit, prefetchable) [size=64K]
>         Expansion ROM at d5700000 [disabled] [size=256K]
>         Capabilities: [48] Power Management version 3
>                 Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA
> PME(D0+,D1-,D2-,D3hot+,D3cold+)
>                 Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=1 PME-
>         Capabilities: [50] Vital Product Data
>                 Product Name: Broadcom NetXtreme Gigabit Ethernet
>                 Read-only fields:
>                         [PN] Part number: BCM95720
>                         [MN] Manufacture ID: 31 30 32 38
>                         [V0] Vendor specific: FFV7.4.8
>                         [V1] Vendor specific: DSV1028VPDR.VER1.0
>                         [V2] Vendor specific: NPY2
>                         [V3] Vendor specific: PMT1
>                         [V4] Vendor specific: NMVBroadcom Corp
>                         [V5] Vendor specific: DTINIC
>                         [V6] Vendor specific: DCM1001008d452101008d45
>                         [RV] Reserved: checksum good, 235 byte(s) reserved
>                 End
>         Capabilities: [58] MSI: Enable- Count=1/8 Maskable- 64bit+
>                 Address: 0000000000000000  Data: 0000
>         Capabilities: [a0] MSI-X: Enable+ Count=17 Masked-
>                 Vector table: BAR=4 offset=00000000
>                 PBA: BAR=4 offset=00001000
>         Capabilities: [ac] Express (v2) Endpoint, MSI 00
>                 DevCap: MaxPayload 256 bytes, PhantFunc 0, Latency L0s <4us,
> L1 <64us
>                         ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset+
>                 DevCtl: Report errors: Correctable- Non-Fatal+ Fatal+
> Unsupported+
>                         RlxdOrd- ExtTag- PhantFunc- AuxPwr+ NoSnoop-
> FLReset-
>                         MaxPayload 256 bytes, MaxReadReq 512 bytes
>                 DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+
> TransPend-
>                 LnkCap: Port #0, Speed 5GT/s, Width x2, ASPM L0s L1, Latency
> L0 <1us, L1 <2us
>                         ClockPM+ Surprise- LLActRep- BwNot-
>                 LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain-
> CommClk+
>                         ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
>                 LnkSta: Speed 5GT/s, Width x1, TrErr- Train- SlotClk+
> DLActive- BWMgmt- ABWMgmt-
>                 DevCap2: Completion Timeout: Range ABCD, TimeoutDis+
>                 DevCtl2: Completion Timeout: 65ms to 210ms, TimeoutDis-
>                 LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance-
> SpeedDis-, Selectable De-emphasis: -6dB
>                          Transmit Margin: Normal Operating Range,
> EnterModifiedCompliance- ComplianceSOS-
>                          Compliance De-emphasis: -6dB
>                 LnkSta2: Current De-emphasis Level: -6dB,
> EqualizationComplete-, EqualizationPhase1-
>                          EqualizationPhase2-, EqualizationPhase3-,
> LinkEqualizationRequest-
>         Capabilities: [100 v1] Advanced Error Reporting
>                 UESta:  DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt-
> RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
>                 UEMsk:  DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt+ UnxCmplt+
> RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
>                 UESvrt: DLP+ SDES+ TLP+ FCP+ CmpltTO+ CmpltAbrt- UnxCmplt-
> RxOF+ MalfTLP+ ECRC+ UnsupReq- ACSViol-
>                 CESta:  RxErr- BadTLP- BadDLLP- Rollover- Timeout-
> NonFatalErr+
>                 CEMsk:  RxErr- BadTLP+ BadDLLP+ Rollover+ Timeout+
> NonFatalErr+
>                 AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+
> ChkEn-
>         Capabilities: [13c v1] Device Serial Number 00-00-90-b1-1c-3f-67-fb
>         Capabilities: [150 v1] Power Budgeting <?>
>         Capabilities: [160 v1] Virtual Channel
>                 Caps:   LPEVC=0 RefClk=100ns PATEntryBits=1
>                 Arb:    Fixed- WRR32- WRR64- WRR128-
>                 Ctrl:   ArbSelect=Fixed
>                 Status: InProgress-
>                 VC0:    Caps:   PATOffset=00 MaxTimeSlots=1 RejSnoopTrans-
>                         Arb:    Fixed- WRR32- WRR64- WRR128- TWRR128-
> WRR256-
>                         Ctrl:   Enable+ ID=0 ArbSelect=Fixed TC/VC=ff
>                         Status: NegoPending- InProgress-
>         Kernel driver in use: tg3
>
>
> Can you please get me some help how to solve the problem?
> If you need more information please let me know.
>
> For answer please Cc me, as I'm not a member of lkml.
>
> Many thanks and regards
> Urban Loesch
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* Re: [PATCH 1/8] net: smc91x: Fix device tree based configuration so it's usable
From: Tony Lindgren @ 2013-11-16 15:16 UTC (permalink / raw)
  To: Mark Rutland
  Cc: linux-arm-kernel@lists.infradead.org, linux-omap@vger.kernel.org,
	Nicolas Pitre, David S. Miller, netdev@vger.kernel.org,
	devicetree@vger.kernel.org
In-Reply-To: <20131114160813.GC10317@atomide.com>

* Tony Lindgren <tony@atomide.com> [131114 08:09]:
> * Mark Rutland <mark.rutland@arm.com> [131114 03:04]:
> > 
> > In the driver the supported access sizes are not mutually exclusive.  It
> > would be nice for the binding to have the same property.
> 
> Hmm indeed. How about we add reg-io-width-mask:
> 
> 	1 = 8-bit access
> 	2 = 16-bit access
> 	4 = 32-bit access
> 	...
> 
> So for a driver to support 8, 16 and 32-bit access the mask would
> be:
> 	reg-io-width-mask = <7>;
> 
> Although the values for reg-io-width would support masks too, it
> might be better to have reg-io-width-mask to avoid confusion.
> 
> Or do you have any better ideas?
>  
> > > +- smsc,nowait : Setup for fast register access with no waits
> > 
> > I'm confused by what this means. When would this be selected, and when
> > wouldn't it be?
> 
> The driver has a module parameter for it and the comments say:
> 
> "nowait  = 0 for normal wait states, 1 eliminates additional wait states"
> 
> Most platforms seem to set it, but the default is to not set it.
> I guess we could that be a module parameter for now as that's a
> timing optimization.

Here's what I was thinking with the reg-io-width-mask. Anybody
have comments on using reg-io-width vs reg-io-width-mask?

Regards,

Tony


From: Tony Lindgren <tony@atomide.com>
Date: Wed, 13 Nov 2013 16:36:37 -0800
Subject: [PATCH] net: smc91x: Fix device tree based configuration so it's usable

Commit 89ce376c6bdc (drivers/net: Use of_match_ptr() macro in smc91x.c)
added minimal device tree support to smc91x, but it's not working on
many platforms because of the lack of some key configuration bits.

Fix the issue by parsing the necessary configuration like the
smc911x driver is doing.

Cc: Nicolas Pitre <nico@fluxnic.net>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: netdev@vger.kernel.org
Cc: devicetree@vger.kernel.org
Signed-off-by: Tony Lindgren <tony@atomide.com>

--- a/Documentation/devicetree/bindings/net/smsc-lan91c111.txt
+++ b/Documentation/devicetree/bindings/net/smsc-lan91c111.txt
@@ -8,3 +8,7 @@ Required properties:
 Optional properties:
 - phy-device : phandle to Ethernet phy
 - local-mac-address : Ethernet mac address to use
+- reg-io-width-mask : Mask of sizes (in bytes) of the IO accesses that
+  are supported on the device.  Valid value for SMSC LAN91c111 are
+  1, 2 or 4.  If it's omitted or invalid, the size would be 2 meaning
+  16-bit access only.
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -82,6 +82,7 @@ static const char version[] =
 #include <linux/mii.h>
 #include <linux/workqueue.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -2189,6 +2190,15 @@ static void smc_release_datacs(struct platform_device *pdev, struct net_device *
 	}
 }
 
+#if IS_BUILTIN(CONFIG_OF)
+static const struct of_device_id smc91x_match[] = {
+	{ .compatible = "smsc,lan91c94", },
+	{ .compatible = "smsc,lan91c111", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, smc91x_match);
+#endif
+
 /*
  * smc_init(void)
  *   Input parameters:
@@ -2203,6 +2213,8 @@ static void smc_release_datacs(struct platform_device *pdev, struct net_device *
 static int smc_drv_probe(struct platform_device *pdev)
 {
 	struct smc91x_platdata *pd = dev_get_platdata(&pdev->dev);
+	struct device_node *np = pdev->dev.of_node;
+	const struct of_device_id *match = NULL;
 	struct smc_local *lp;
 	struct net_device *ndev;
 	struct resource *res, *ires;
@@ -2222,11 +2234,31 @@ static int smc_drv_probe(struct platform_device *pdev)
 	 */
 
 	lp = netdev_priv(ndev);
+	lp->cfg.flags = 0;
 
 	if (pd) {
 		memcpy(&lp->cfg, pd, sizeof(lp->cfg));
 		lp->io_shift = SMC91X_IO_SHIFT(lp->cfg.flags);
-	} else {
+	}
+
+#if IS_BUILTIN(CONFIG_OF)
+	match = of_match_device(of_match_ptr(smc91x_match), &pdev->dev);
+	if (match) {
+		u32 val;
+
+		of_property_read_u32(np, "reg-io-width", &val);
+		if (val == 0)
+			lp->cfg.flags |= SMC91X_USE_16BIT;
+		if (val & 1)
+			lp->cfg.flags |= SMC91X_USE_8BIT;
+		if (val & 2)
+			lp->cfg.flags |= SMC91X_USE_16BIT;
+		if (val & 4)
+			lp->cfg.flags |= SMC91X_USE_32BIT;
+	}
+#endif
+
+	if (!pd && !match) {
 		lp->cfg.flags |= (SMC_CAN_USE_8BIT)  ? SMC91X_USE_8BIT  : 0;
 		lp->cfg.flags |= (SMC_CAN_USE_16BIT) ? SMC91X_USE_16BIT : 0;
 		lp->cfg.flags |= (SMC_CAN_USE_32BIT) ? SMC91X_USE_32BIT : 0;
@@ -2375,15 +2407,6 @@ static int smc_drv_resume(struct device *dev)
 	return 0;
 }
 
-#ifdef CONFIG_OF
-static const struct of_device_id smc91x_match[] = {
-	{ .compatible = "smsc,lan91c94", },
-	{ .compatible = "smsc,lan91c111", },
-	{},
-};
-MODULE_DEVICE_TABLE(of, smc91x_match);
-#endif
-
 static struct dev_pm_ops smc_drv_pm_ops = {
 	.suspend	= smc_drv_suspend,
 	.resume		= smc_drv_resume,

^ permalink raw reply

* Re: [PATCH tip/core/rcu 11/14] bonding/bond_main: Apply ACCESS_ONCE() to avoid sparse false positive
From: Paul E. McKenney @ 2013-11-16 15:21 UTC (permalink / raw)
  To: Ding Tianhong
  Cc: Stephen Hemminger, tglx, laijs, edumazet, David S. Miller, peterz,
	fweisbec, bridge, linux-kernel, rostedt, josh, dhowells, sbw, niv,
	netdev, mathieu.desnoyers, dipankar, darren, akpm, mingo
In-Reply-To: <5286F550.10900@gmail.com>

On Sat, Nov 16, 2013 at 12:32:16PM +0800, Ding Tianhong wrote:
> 于 2013/11/16 8:40, Paul E. McKenney 写道:
> > From: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
> >
> > The sparse checking for rcu_assign_pointer() was recently upgraded
> > to reject non-__kernel address spaces.  This also rejects __rcu,
> > which is almost always the right thing to do.  However, the uses in
> > bond_change_active_slave() and __bond_release_one() are legitimate:
> > They are assigning a pointer to an element from an RCU-protected list
> > (or a NULL pointer), and all elements of this list are already visible
> > to caller.
> >
> > This commit therefore silences these false positives either by laundering
> > the pointers using ACCESS_ONCE() as suggested by Eric Dumazet and Josh
> > Triplett, or by using RCU_INIT_POINTER() for NULL pointer assignments.
> 
> I think it is fit for net-next.

Thank you!

If this is queued there, I would be happy to drop it from my tree.
There are no dependencies on anything in my tree.

							Thanx, Paul

> > Reported-by: kbuild test robot <fengguang.wu@intel.com>
> > Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> > Cc: Stephen Hemminger <stephen@networkplumber.org>
> > Cc: "David S. Miller" <davem@davemloft.net>
> > Cc: bridge@lists.linux-foundation.org
> > Cc: netdev@vger.kernel.org
> > ---
> >  drivers/net/bonding/bond_main.c | 5 +++--
> >  1 file changed, 3 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> > index 72df399c4ab3..bbd7fd3e46fe 100644
> > --- a/drivers/net/bonding/bond_main.c
> > +++ b/drivers/net/bonding/bond_main.c
> > @@ -890,7 +890,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
> >  		if (new_active)
> >  			bond_set_slave_active_flags(new_active);
> >  	} else {
> > -		rcu_assign_pointer(bond->curr_active_slave, new_active);
> > +		/* Both --rcu and visible, so ACCESS_ONCE() is OK. */
> > +		ACCESS_ONCE(bond->curr_active_slave) = new_active;
> >  	}
> >  
> >  	if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
> > @@ -1801,7 +1802,7 @@ static int __bond_release_one(struct net_device *bond_dev,
> >  	}
> >  
> >  	if (all) {
> > -		rcu_assign_pointer(bond->curr_active_slave, NULL);
> > +		RCU_INIT_POINTER(bond->curr_active_slave, NULL);
> >  	} else if (oldcurrent == slave) {
> >  		/*
> >  		 * Note that we hold RTNL over this sequence, so there
> 

^ permalink raw reply

* Re: [PATCH v3] net: Do not include padding in TCP GRO checksum
From: Alexander Duyck @ 2013-11-16 17:02 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Alexander Duyck, davem, netdev, edumazet
In-Reply-To: <20131116064611.GA12146@gondor.apana.org.au>

On 11/15/2013 10:46 PM, Herbert Xu wrote:
> On Fri, Nov 15, 2013 at 08:10:00PM -0800, Alexander Duyck wrote:
>> The case I am addressing is padding added by the remote side. 
>> Specifically in my case I was seeing TCP frames without options that
>> were padded up to 60 bytes from a netperf TCP_RR test.  I messed up the
>> padding/checksum logic so it was making the same mistake in the Tx
>> checksum logic in the driver that I caught here in GRO.  As a result I
>> was seeing checksum errors errors in wireshark, but noticed they were
>> being accepted by the stack as valid.
> OK great.  So this isn't normal data that we expect to aggregate.

Sorry, I thought that was obvious.  The check in the IPv4/IPv6 GRO
functions always make it so that we flush any frames that contain padding.

> In that case the simplest solution is to skip the checksum check
> altogether.  We only require it if the packet is going to be merged.
>
> So how about something like this?
>
> gro: Only verify TCP checksums for candidates
>
> In some cases we may receive IP packets that are longer than
> their stated lengths.  Such packets are never merged in GRO.
> However, we may end up computing their checksums incorrectly
> and end up allowing packets with a bogus checksum enter our
> stack with the checksum status set as verified.
>
> Since such packets are rare and not performance-critical, this
> patch simply skips the checksum verification for them.
>
> Reported-by: Alexander Duyck <alexander.h.duyck@intel.com>
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
>
> diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
> index a2b68a1..55aeec9 100644
> --- a/net/ipv4/tcp_offload.c
> +++ b/net/ipv4/tcp_offload.c
> @@ -276,6 +276,10 @@ static struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *
>  	__wsum wsum;
>  	__sum16 sum;
>  
> +	/* Don't bother verifying checksum if we're going to flush anyway. */
> +	if (NAPI_GRO_CB(skb)->flush)
> +		goto skip_csum;
> +
>  	switch (skb->ip_summed) {
>  	case CHECKSUM_COMPLETE:
>  		if (!tcp_v4_check(skb_gro_len(skb), iph->saddr, iph->daddr,
> @@ -301,6 +305,7 @@ flush:
>  		break;
>  	}
>  
> +skip_csum:
>  	return tcp_gro_receive(head, skb);
>  }
>  
> diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c
> index c1097c7..71923d1 100644
> --- a/net/ipv6/tcpv6_offload.c
> +++ b/net/ipv6/tcpv6_offload.c
> @@ -39,6 +39,10 @@ static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
>  	__wsum wsum;
>  	__sum16 sum;
>  
> +	/* Don't bother verifying checksum if we're going to flush anyway. */
> +	if (NAPI_GRO_CB(skb)->flush)
> +		goto skip_csum;
> +
>  	switch (skb->ip_summed) {
>  	case CHECKSUM_COMPLETE:
>  		if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
> @@ -65,6 +69,7 @@ flush:
>  		break;
>  	}
>  
> +skip_csum:
>  	return tcp_gro_receive(head, skb);
>  }
>
> Thanks,

This should work.  I was just playing it safe in the patches I was
submitting by trying not to alter the behaviour.  As long as it is safe
to push something with a bad checksum and the flush bit I am fine with this.

That being the case though, why don't we set the flush flag on detecting
a bad checksum and hand it off to tcp_gro_receive instead of returning
NULL?  It seems like it would be in our interest to flush the flow and
then report the bad checksum instead of keeping the flow and handing off
the bad checksum to the stack.

Thanks,

Alex

^ permalink raw reply

* [RFC 4/8] hsr: don't call genl_unregister_mc_group()
From: Johannes Berg @ 2013-11-16 17:03 UTC (permalink / raw)
  To: netdev; +Cc: Johannes Berg
In-Reply-To: <1384621429-24543-1-git-send-email-johannes@sipsolutions.net>

From: Johannes Berg <johannes.berg@intel.com>

There's no need to unregister the multicast group if the
generic netlink family is registered immediately after.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/hsr/hsr_netlink.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
index f182260..908e335 100644
--- a/net/hsr/hsr_netlink.c
+++ b/net/hsr/hsr_netlink.c
@@ -435,9 +435,7 @@ fail_rtnl_link_register:
 
 void __exit hsr_netlink_exit(void)
 {
-	genl_unregister_mc_group(&hsr_genl_family, &hsr_network_genl_mcgrp);
 	genl_unregister_family(&hsr_genl_family);
-
 	rtnl_link_unregister(&hsr_link_ops);
 }
 
-- 
1.8.4.rc3

^ permalink raw reply related

* [RFC 3/8] quota/genetlink: use proper genetlink multicast APIs
From: Johannes Berg @ 2013-11-16 17:03 UTC (permalink / raw)
  To: netdev; +Cc: Johannes Berg, Jan Kara
In-Reply-To: <1384621429-24543-1-git-send-email-johannes@sipsolutions.net>

From: Johannes Berg <johannes.berg@intel.com>

The quota code is abusing the genetlink API and is using
its family ID as the multicast group ID, which is invalid
and may belong to somebody else (and likely will.)

Make the quota code use the correct API, but since this
is already used as-is by userspace, reserve a family ID
for this code and also reserve that group ID to not break
userspace assumptions.

Cc: Jan Kara <jack@suse.cz>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 fs/quota/netlink.c             | 17 +++++++++++++++--
 include/uapi/linux/genetlink.h |  1 +
 net/netlink/genetlink.c        | 10 ++++++++--
 3 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
index 16e8abb..b261ce4 100644
--- a/fs/quota/netlink.c
+++ b/fs/quota/netlink.c
@@ -11,13 +11,23 @@
 
 /* Netlink family structure for quota */
 static struct genl_family quota_genl_family = {
-	.id = GENL_ID_GENERATE,
+	/*
+	 * Needed due to multicast group ID abuse - old code assumed
+	 * the family ID was also a valid multicast group ID (which
+	 * isn't true) and userspace might thus rely on it. Assign a
+	 * static ID for this group to make dealing with that easier.
+	 */
+	.id = GENL_ID_VFS_DQUOT,
 	.hdrsize = 0,
 	.name = "VFS_DQUOT",
 	.version = 1,
 	.maxattr = QUOTA_NL_A_MAX,
 };
 
+static struct genl_multicast_group quota_mcgrp = {
+	.name = "VFS_DQUOT", /* not really used */
+};
+
 /**
  * quota_send_warning - Send warning to userspace about exceeded quota
  * @type: The quota type: USRQQUOTA, GRPQUOTA,...
@@ -78,7 +88,7 @@ void quota_send_warning(struct kqid qid, dev_t dev,
 		goto attr_err_out;
 	genlmsg_end(skb, msg_head);
 
-	genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS);
+	genlmsg_multicast(skb, 0, quota_mcgrp.id, GFP_NOFS);
 	return;
 attr_err_out:
 	printk(KERN_ERR "VFS: Not enough space to compose quota message!\n");
@@ -92,6 +102,9 @@ static int __init quota_init(void)
 	if (genl_register_family(&quota_genl_family) != 0)
 		printk(KERN_ERR
 		       "VFS: Failed to create quota netlink interface.\n");
+	if (genl_register_mc_group(&quota_genl_family, &quota_mcgrp))
+		printk(KERN_ERR
+		       "VFS: Failed to register quota mcast group.\n");
 	return 0;
 };
 
diff --git a/include/uapi/linux/genetlink.h b/include/uapi/linux/genetlink.h
index c880a41..1af72d82 100644
--- a/include/uapi/linux/genetlink.h
+++ b/include/uapi/linux/genetlink.h
@@ -27,6 +27,7 @@ struct genlmsghdr {
  */
 #define GENL_ID_GENERATE	0
 #define GENL_ID_CTRL		NLMSG_MIN_TYPE
+#define GENL_ID_VFS_DQUOT	(NLMSG_MIN_TYPE + 1)
 
 /**************************************************************************
  * Controller
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 8a2ed2c..d0757c6 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -69,8 +69,11 @@ static struct list_head family_ht[GENL_FAM_TAB_SIZE];
  * abuses the API and thinks it can statically use group 1.
  * That group will typically conflict with other groups that
  * any proper users use.
+ * Bit 17 is marked as already used since the VFS quota code
+ * also abused this API and relied on family == group ID, we
+ * cater to that by giving it a static family and group ID.
  */
-static unsigned long mc_group_start = 0x3;
+static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_VFS_DQUOT);
 static unsigned long *mc_groups = &mc_group_start;
 static unsigned long mc_groups_longs = 1;
 
@@ -130,7 +133,8 @@ static u16 genl_generate_id(void)
 	int i;
 
 	for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) {
-		if (!genl_family_find_byid(id_gen_idx))
+		if (id_gen_idx != GENL_ID_VFS_DQUOT &&
+		    !genl_family_find_byid(id_gen_idx))
 			return id_gen_idx;
 		if (++id_gen_idx > GENL_MAX_ID)
 			id_gen_idx = GENL_MIN_ID;
@@ -169,6 +173,8 @@ int genl_register_mc_group(struct genl_family *family,
 		id = GENL_ID_CTRL;
 	else if (strcmp(family->name, "NET_DM") == 0)
 		id = 1;
+	else if (strcmp(family->name, "VFS_DQUOT") == 0)
+		id = GENL_ID_VFS_DQUOT;
 	else
 		id = find_first_zero_bit(mc_groups,
 					 mc_groups_longs * BITS_PER_LONG);
-- 
1.8.4.rc3

^ permalink raw reply related

* [RFC 1/8] genetlink: only pass array to genl_register_family_with_ops()
From: Johannes Berg @ 2013-11-16 17:03 UTC (permalink / raw)
  To: netdev; +Cc: Johannes Berg
In-Reply-To: <1384621429-24543-1-git-send-email-johannes@sipsolutions.net>

From: Johannes Berg <johannes.berg@intel.com>

As suggested by David Miller, make genl_register_family_with_ops()
a macro and pass only the array, evaluating ARRAY_SIZE() in the
macro, this is a little safer.

The openvswitch has some indirection, assing ops/n_ops directly in
that code. This might ultimately just assign the pointers in the
family initializations, saving the struct genl_family_and_ops and
code (once mcast groups are handled differently.)

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/net/team/team.c               |  3 +--
 drivers/net/wireless/mac80211_hwsim.c |  3 +--
 fs/dlm/netlink.c                      | 10 ++++++----
 include/linux/genl_magic_func.h       |  3 +--
 include/net/genetlink.h               |  8 ++++++--
 kernel/taskstats.c                    |  3 +--
 net/core/drop_monitor.c               |  3 +--
 net/hsr/hsr_netlink.c                 |  3 +--
 net/ieee802154/netlink.c              |  3 +--
 net/ipv4/tcp_metrics.c                |  3 +--
 net/irda/irnetlink.c                  |  3 +--
 net/l2tp/l2tp_netlink.c               |  7 +------
 net/netfilter/ipvs/ip_vs_ctl.c        |  2 +-
 net/netlabel/netlabel_cipso_v4.c      |  2 +-
 net/netlabel/netlabel_mgmt.c          |  2 +-
 net/netlabel/netlabel_unlabeled.c     |  2 +-
 net/netlink/genetlink.c               | 14 ++++++++------
 net/nfc/netlink.c                     |  3 +--
 net/openvswitch/datapath.c            |  5 +++--
 net/tipc/netlink.c                    | 11 ++++++-----
 net/wimax/stack.c                     |  4 ++--
 net/wireless/nl80211.c                |  3 +--
 22 files changed, 47 insertions(+), 53 deletions(-)

diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 6390254..f55758b 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -2699,8 +2699,7 @@ static int team_nl_init(void)
 {
 	int err;
 
-	err = genl_register_family_with_ops(&team_nl_family, team_nl_ops,
-					    ARRAY_SIZE(team_nl_ops));
+	err = genl_register_family_with_ops(&team_nl_family, team_nl_ops);
 	if (err)
 		return err;
 
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index cfc3fda..9df7bc9 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -2148,8 +2148,7 @@ static int hwsim_init_netlink(void)
 
 	printk(KERN_INFO "mac80211_hwsim: initializing netlink\n");
 
-	rc = genl_register_family_with_ops(&hwsim_genl_family,
-		hwsim_ops, ARRAY_SIZE(hwsim_ops));
+	rc = genl_register_family_with_ops(&hwsim_genl_family, hwsim_ops);
 	if (rc)
 		goto failure;
 
diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c
index 60a3278..e7cfbaf 100644
--- a/fs/dlm/netlink.c
+++ b/fs/dlm/netlink.c
@@ -74,14 +74,16 @@ static int user_cmd(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 }
 
-static struct genl_ops dlm_nl_ops = {
-	.cmd		= DLM_CMD_HELLO,
-	.doit		= user_cmd,
+static struct genl_ops dlm_nl_ops[] = {
+	{
+		.cmd	= DLM_CMD_HELLO,
+		.doit	= user_cmd,
+	},
 };
 
 int __init dlm_netlink_init(void)
 {
-	return genl_register_family_with_ops(&family, &dlm_nl_ops, 1);
+	return genl_register_family_with_ops(&family, dlm_nl_ops);
 }
 
 void dlm_netlink_exit(void)
diff --git a/include/linux/genl_magic_func.h b/include/linux/genl_magic_func.h
index 023bc34..4708603 100644
--- a/include/linux/genl_magic_func.h
+++ b/include/linux/genl_magic_func.h
@@ -293,8 +293,7 @@ static int CONCAT_(GENL_MAGIC_FAMILY, _genl_multicast_ ## group)(	\
 
 int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void)
 {
-	int err = genl_register_family_with_ops(&ZZZ_genl_family,
-		ZZZ_genl_ops, ARRAY_SIZE(ZZZ_genl_ops));
+	int err = genl_register_family_with_ops(&ZZZ_genl_family, ZZZ_genl_ops);
 	if (err)
 		return err;
 #undef GENL_mc_group
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index e96385d..9bd52a4c 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -152,8 +152,9 @@ static inline int genl_register_family(struct genl_family *family)
  *
  * Return 0 on success or a negative error code.
  */
-static inline int genl_register_family_with_ops(struct genl_family *family,
-	const struct genl_ops *ops, size_t n_ops)
+static inline int _genl_register_family_with_ops(struct genl_family *family,
+						 const struct genl_ops *ops,
+						 size_t n_ops)
 {
 	family->module = THIS_MODULE;
 	family->ops = ops;
@@ -161,6 +162,9 @@ static inline int genl_register_family_with_ops(struct genl_family *family,
 	return __genl_register_family(family);
 }
 
+#define genl_register_family_with_ops(family, ops)	\
+	_genl_register_family_with_ops((family), (ops), ARRAY_SIZE(ops))
+
 int genl_unregister_family(struct genl_family *family);
 int genl_register_mc_group(struct genl_family *family,
 			   struct genl_multicast_group *grp);
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 76595cd..13d2f7c 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -703,8 +703,7 @@ static int __init taskstats_init(void)
 {
 	int rc;
 
-	rc = genl_register_family_with_ops(&family, taskstats_ops,
-					   ARRAY_SIZE(taskstats_ops));
+	rc = genl_register_family_with_ops(&family, taskstats_ops);
 	if (rc)
 		return rc;
 
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
index f9fe2f2..0efc502 100644
--- a/net/core/drop_monitor.c
+++ b/net/core/drop_monitor.c
@@ -365,8 +365,7 @@ static int __init init_net_drop_monitor(void)
 	}
 
 	rc = genl_register_family_with_ops(&net_drop_monitor_family,
-					   dropmon_ops,
-					   ARRAY_SIZE(dropmon_ops));
+					   dropmon_ops);
 	if (rc) {
 		pr_err("Could not create drop monitor netlink family\n");
 		return rc;
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
index 3b9205d..f182260 100644
--- a/net/hsr/hsr_netlink.c
+++ b/net/hsr/hsr_netlink.c
@@ -414,8 +414,7 @@ int __init hsr_netlink_init(void)
 	if (rc)
 		goto fail_rtnl_link_register;
 
-	rc = genl_register_family_with_ops(&hsr_genl_family, hsr_ops,
-					   ARRAY_SIZE(hsr_ops));
+	rc = genl_register_family_with_ops(&hsr_genl_family, hsr_ops);
 	if (rc)
 		goto fail_genl_register_family;
 
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index 3ffcdbb..1a81709 100644
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -129,8 +129,7 @@ int __init ieee802154_nl_init(void)
 {
 	int rc;
 
-	rc = genl_register_family_with_ops(&nl802154_family, ieee8021154_ops,
-					   ARRAY_SIZE(ieee8021154_ops));
+	rc = genl_register_family_with_ops(&nl802154_family, ieee8021154_ops);
 	if (rc)
 		return rc;
 
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c
index 8c121b5..0649373 100644
--- a/net/ipv4/tcp_metrics.c
+++ b/net/ipv4/tcp_metrics.c
@@ -1082,8 +1082,7 @@ void __init tcp_metrics_init(void)
 	if (ret < 0)
 		goto cleanup;
 	ret = genl_register_family_with_ops(&tcp_metrics_nl_family,
-					    tcp_metrics_nl_ops,
-					    ARRAY_SIZE(tcp_metrics_nl_ops));
+					    tcp_metrics_nl_ops);
 	if (ret < 0)
 		goto cleanup_subsys;
 	return;
diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c
index bf5d7d4..a37b81f 100644
--- a/net/irda/irnetlink.c
+++ b/net/irda/irnetlink.c
@@ -149,8 +149,7 @@ static const struct genl_ops irda_nl_ops[] = {
 
 int irda_nl_register(void)
 {
-	return genl_register_family_with_ops(&irda_nl_family,
-		irda_nl_ops, ARRAY_SIZE(irda_nl_ops));
+	return genl_register_family_with_ops(&irda_nl_family, irda_nl_ops);
 }
 
 void irda_nl_unregister(void)
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index 57db66e..4cfd722 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -887,13 +887,8 @@ EXPORT_SYMBOL_GPL(l2tp_nl_unregister_ops);
 
 static int l2tp_nl_init(void)
 {
-	int err;
-
 	pr_info("L2TP netlink interface\n");
-	err = genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops,
-					    ARRAY_SIZE(l2tp_nl_ops));
-
-	return err;
+	return genl_register_family_with_ops(&l2tp_nl_family, l2tp_nl_ops);
 }
 
 static void l2tp_nl_cleanup(void)
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index fc8a04e..3934987 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -3666,7 +3666,7 @@ static const struct genl_ops ip_vs_genl_ops[] __read_mostly = {
 static int __init ip_vs_genl_register(void)
 {
 	return genl_register_family_with_ops(&ip_vs_genl_family,
-		ip_vs_genl_ops, ARRAY_SIZE(ip_vs_genl_ops));
+					     ip_vs_genl_ops);
 }
 
 static void ip_vs_genl_unregister(void)
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index 7066917..69345ce 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -783,5 +783,5 @@ static const struct genl_ops netlbl_cipsov4_ops[] = {
 int __init netlbl_cipsov4_genl_init(void)
 {
 	return genl_register_family_with_ops(&netlbl_cipsov4_gnl_family,
-		netlbl_cipsov4_ops, ARRAY_SIZE(netlbl_cipsov4_ops));
+					     netlbl_cipsov4_ops);
 }
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index 7de6f66..8ef83ee 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -779,5 +779,5 @@ static const struct genl_ops netlbl_mgmt_genl_ops[] = {
 int __init netlbl_mgmt_genl_init(void)
 {
 	return genl_register_family_with_ops(&netlbl_mgmt_gnl_family,
-		netlbl_mgmt_genl_ops, ARRAY_SIZE(netlbl_mgmt_genl_ops));
+					     netlbl_mgmt_genl_ops);
 }
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 76ee925..43817d7 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -1397,7 +1397,7 @@ static const struct genl_ops netlbl_unlabel_genl_ops[] = {
 int __init netlbl_unlabel_genl_init(void)
 {
 	return genl_register_family_with_ops(&netlbl_unlabel_gnl_family,
-		netlbl_unlabel_genl_ops, ARRAY_SIZE(netlbl_unlabel_genl_ops));
+					     netlbl_unlabel_genl_ops);
 }
 
 /*
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index f07eb56..2b57aee 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -906,11 +906,13 @@ static int genl_ctrl_event(int event, void *data)
 	return 0;
 }
 
-static struct genl_ops genl_ctrl_ops = {
-	.cmd		= CTRL_CMD_GETFAMILY,
-	.doit		= ctrl_getfamily,
-	.dumpit		= ctrl_dumpfamily,
-	.policy		= ctrl_policy,
+static struct genl_ops genl_ctrl_ops[] = {
+	{
+		.cmd		= CTRL_CMD_GETFAMILY,
+		.doit		= ctrl_getfamily,
+		.dumpit		= ctrl_dumpfamily,
+		.policy		= ctrl_policy,
+	},
 };
 
 static struct genl_multicast_group notify_grp = {
@@ -954,7 +956,7 @@ static int __init genl_init(void)
 	for (i = 0; i < GENL_FAM_TAB_SIZE; i++)
 		INIT_LIST_HEAD(&family_ht[i]);
 
-	err = genl_register_family_with_ops(&genl_ctrl, &genl_ctrl_ops, 1);
+	err = genl_register_family_with_ops(&genl_ctrl, genl_ctrl_ops);
 	if (err < 0)
 		goto problem;
 
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index f558561..fe6760d 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -1536,8 +1536,7 @@ int __init nfc_genl_init(void)
 {
 	int rc;
 
-	rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops,
-					   ARRAY_SIZE(nfc_genl_ops));
+	rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops);
 	if (rc)
 		return rc;
 
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 91e1c92..8ec8b73 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -1817,8 +1817,9 @@ static int dp_register_genl(void)
 	for (i = 0; i < ARRAY_SIZE(dp_genl_families); i++) {
 		const struct genl_family_and_ops *f = &dp_genl_families[i];
 
-		err = genl_register_family_with_ops(f->family, f->ops,
-						    f->n_ops);
+		f->family->ops = f->ops;
+		f->family->n_ops = f->n_ops;
+		err = genl_register_family(f->family);
 		if (err)
 			goto error;
 		n_registered++;
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index 8bcd498..9f72a63 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -76,9 +76,11 @@ static struct genl_family tipc_genl_family = {
 	.maxattr	= 0,
 };
 
-static struct genl_ops tipc_genl_ops = {
-	.cmd		= TIPC_GENL_CMD,
-	.doit		= handle_cmd,
+static struct genl_ops tipc_genl_ops[] = {
+	{
+		.cmd		= TIPC_GENL_CMD,
+		.doit		= handle_cmd,
+	},
 };
 
 static int tipc_genl_family_registered;
@@ -87,8 +89,7 @@ int tipc_netlink_start(void)
 {
 	int res;
 
-	res = genl_register_family_with_ops(&tipc_genl_family,
-		&tipc_genl_ops, 1);
+	res = genl_register_family_with_ops(&tipc_genl_family, tipc_genl_ops);
 	if (res) {
 		pr_err("Failed to register netlink interface\n");
 		return res;
diff --git a/net/wimax/stack.c b/net/wimax/stack.c
index 47170c9..6328afe 100644
--- a/net/wimax/stack.c
+++ b/net/wimax/stack.c
@@ -597,8 +597,8 @@ int __init wimax_subsys_init(void)
 
 	snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name),
 		 "WiMAX");
-	result = genl_register_family_with_ops(&wimax_gnl_family, wimax_gnl_ops,
-					       ARRAY_SIZE(wimax_gnl_ops));
+	result = genl_register_family_with_ops(&wimax_gnl_family,
+					       wimax_gnl_ops);
 	if (unlikely(result < 0)) {
 		printk(KERN_ERR "cannot register generic netlink family: %d\n",
 		       result);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 58c43c8..1b6c5dd 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -11329,8 +11329,7 @@ int nl80211_init(void)
 {
 	int err;
 
-	err = genl_register_family_with_ops(&nl80211_fam,
-		nl80211_ops, ARRAY_SIZE(nl80211_ops));
+	err = genl_register_family_with_ops(&nl80211_fam, nl80211_ops);
 	if (err)
 		return err;
 
-- 
1.8.4.rc3

^ permalink raw reply related

* [RFC 5/8] genetlink: remove genl_unregister_mc_group()
From: Johannes Berg @ 2013-11-16 17:03 UTC (permalink / raw)
  To: netdev; +Cc: Johannes Berg
In-Reply-To: <1384621429-24543-1-git-send-email-johannes@sipsolutions.net>

From: Johannes Berg <johannes.berg@intel.com>

There are no users of this API remaining, and we'll soon
change group registration to be static (like ops are now)

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/genetlink.h |  2 --
 net/netlink/genetlink.c | 23 -----------------------
 2 files changed, 25 deletions(-)

diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index 9bd52a4c..067569d 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -168,8 +168,6 @@ static inline int _genl_register_family_with_ops(struct genl_family *family,
 int genl_unregister_family(struct genl_family *family);
 int genl_register_mc_group(struct genl_family *family,
 			   struct genl_multicast_group *grp);
-void genl_unregister_mc_group(struct genl_family *family,
-			      struct genl_multicast_group *grp);
 void genl_notify(struct sk_buff *skb, struct net *net, u32 portid,
 		 u32 group, struct nlmsghdr *nlh, gfp_t flags);
 
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index d0757c6..9fa0607 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -265,29 +265,6 @@ static void __genl_unregister_mc_group(struct genl_family *family,
 	grp->family = NULL;
 }
 
-/**
- * genl_unregister_mc_group - unregister a multicast group
- *
- * Unregisters the specified multicast group and notifies userspace
- * about it. All current listeners on the group are removed.
- *
- * Note: It is not necessary to unregister all multicast groups before
- *       unregistering the family, unregistering the family will cause
- *       all assigned multicast groups to be unregistered automatically.
- *
- * @family: Generic netlink family the group belongs to.
- * @grp: The group to unregister, must have been registered successfully
- *	 previously.
- */
-void genl_unregister_mc_group(struct genl_family *family,
-			      struct genl_multicast_group *grp)
-{
-	genl_lock_all();
-	__genl_unregister_mc_group(family, grp);
-	genl_unlock_all();
-}
-EXPORT_SYMBOL(genl_unregister_mc_group);
-
 static void genl_unregister_mc_groups(struct genl_family *family)
 {
 	struct genl_multicast_group *grp, *tmp;
-- 
1.8.4.rc3

^ permalink raw reply related

* [RFC 6/8] genetlink: remove family pointer from genl_multicast_group
From: Johannes Berg @ 2013-11-16 17:03 UTC (permalink / raw)
  To: netdev; +Cc: Johannes Berg
In-Reply-To: <1384621429-24543-1-git-send-email-johannes@sipsolutions.net>

From: Johannes Berg <johannes.berg@intel.com>

There's no reason to have the family pointer there since it
can just be passed internally where needed, so remove it.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/genetlink.h |  2 --
 net/netlink/genetlink.c | 38 ++++++++++++++++++--------------------
 2 files changed, 18 insertions(+), 22 deletions(-)

diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index 067569d..d8a8b1f 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -13,10 +13,8 @@
  * @id: multicast group ID, assigned by the core, to use with
  *      genlmsg_multicast().
  * @list: list entry for linking
- * @family: pointer to family, need not be set before registering
  */
 struct genl_multicast_group {
-	struct genl_family	*family;	/* private */
 	struct list_head	list;		/* private */
 	char			name[GENL_NAMSIZ];
 	u32			id;
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 9fa0607..5e81562 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -77,7 +77,8 @@ static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_VFS_DQUOT);
 static unsigned long *mc_groups = &mc_group_start;
 static unsigned long mc_groups_longs = 1;
 
-static int genl_ctrl_event(int event, void *data);
+static int genl_ctrl_event(int event, struct genl_family *family,
+			   struct genl_multicast_group *grp);
 
 static inline unsigned int genl_family_hash(unsigned int id)
 {
@@ -235,9 +236,8 @@ int genl_register_mc_group(struct genl_family *family,
 	grp->id = id;
 	set_bit(id, mc_groups);
 	list_add_tail(&grp->list, &family->mcast_groups);
-	grp->family = family;
 
-	genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp);
+	genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, family, grp);
  out:
 	genl_unlock_all();
 	return err;
@@ -248,7 +248,6 @@ static void __genl_unregister_mc_group(struct genl_family *family,
 				       struct genl_multicast_group *grp)
 {
 	struct net *net;
-	BUG_ON(grp->family != family);
 
 	netlink_table_grab();
 	rcu_read_lock();
@@ -260,9 +259,8 @@ static void __genl_unregister_mc_group(struct genl_family *family,
 	if (grp->id != 1)
 		clear_bit(grp->id, mc_groups);
 	list_del(&grp->list);
-	genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
+	genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, family, grp);
 	grp->id = 0;
-	grp->family = NULL;
 }
 
 static void genl_unregister_mc_groups(struct genl_family *family)
@@ -364,7 +362,7 @@ int __genl_register_family(struct genl_family *family)
 	list_add_tail(&family->family_list, genl_family_chain(family->id));
 	genl_unlock_all();
 
-	genl_ctrl_event(CTRL_CMD_NEWFAMILY, family);
+	genl_ctrl_event(CTRL_CMD_NEWFAMILY, family, NULL);
 
 	return 0;
 
@@ -400,7 +398,7 @@ int genl_unregister_family(struct genl_family *family)
 		genl_unlock_all();
 
 		kfree(family->attrbuf);
-		genl_ctrl_event(CTRL_CMD_DELFAMILY, family);
+		genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL);
 		return 0;
 	}
 
@@ -693,7 +691,8 @@ nla_put_failure:
 	return -EMSGSIZE;
 }
 
-static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 portid,
+static int ctrl_fill_mcgrp_info(struct genl_family *family,
+				struct genl_multicast_group *grp, u32 portid,
 				u32 seq, u32 flags, struct sk_buff *skb,
 				u8 cmd)
 {
@@ -705,8 +704,8 @@ static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 portid,
 	if (hdr == NULL)
 		return -1;
 
-	if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, grp->family->name) ||
-	    nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, grp->family->id))
+	if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) ||
+	    nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id))
 		goto nla_put_failure;
 
 	nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
@@ -783,7 +782,8 @@ static struct sk_buff *ctrl_build_family_msg(struct genl_family *family,
 	return skb;
 }
 
-static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp,
+static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_family *family,
+					    struct genl_multicast_group *grp,
 					    u32 portid, int seq, u8 cmd)
 {
 	struct sk_buff *skb;
@@ -793,7 +793,7 @@ static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp,
 	if (skb == NULL)
 		return ERR_PTR(-ENOBUFS);
 
-	err = ctrl_fill_mcgrp_info(grp, portid, seq, 0, skb, cmd);
+	err = ctrl_fill_mcgrp_info(family, grp, portid, seq, 0, skb, cmd);
 	if (err < 0) {
 		nlmsg_free(skb);
 		return ERR_PTR(err);
@@ -855,11 +855,10 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
 	return genlmsg_reply(msg, info);
 }
 
-static int genl_ctrl_event(int event, void *data)
+static int genl_ctrl_event(int event, struct genl_family *family,
+			   struct genl_multicast_group *grp)
 {
 	struct sk_buff *msg;
-	struct genl_family *family;
-	struct genl_multicast_group *grp;
 
 	/* genl is still initialising */
 	if (!init_net.genl_sock)
@@ -868,14 +867,13 @@ static int genl_ctrl_event(int event, void *data)
 	switch (event) {
 	case CTRL_CMD_NEWFAMILY:
 	case CTRL_CMD_DELFAMILY:
-		family = data;
+		WARN_ON(grp);
 		msg = ctrl_build_family_msg(family, 0, 0, event);
 		break;
 	case CTRL_CMD_NEWMCAST_GRP:
 	case CTRL_CMD_DELMCAST_GRP:
-		grp = data;
-		family = grp->family;
-		msg = ctrl_build_mcgrp_msg(data, 0, 0, event);
+		BUG_ON(!grp);
+		msg = ctrl_build_mcgrp_msg(family, grp, 0, 0, event);
 		break;
 	default:
 		return -EINVAL;
-- 
1.8.4.rc3

^ permalink raw reply related

* [RFC 0/8] generic netlink multicast group cleanup
From: Johannes Berg @ 2013-11-16 17:03 UTC (permalink / raw)
  To: netdev

So I looked at the generic netlink multicast groups, and it turns out
that two users (drop_monitor and quota) abuse the groups.

Making the groups static has multiple benefits from space usage and    
initialization code complexity point of view, but also makes it much
harder to abuse the groups like that again in the future since each
call using them can check the group is actually valid in the family.

johannes

^ permalink raw reply

* [RFC 2/8] drop_monitor/genetlink: use proper genetlink multicast APIs
From: Johannes Berg @ 2013-11-16 17:03 UTC (permalink / raw)
  To: netdev; +Cc: Johannes Berg, Neil Horman
In-Reply-To: <1384621429-24543-1-git-send-email-johannes@sipsolutions.net>

From: Johannes Berg <johannes.berg@intel.com>

The drop monitor code is abusing the genetlink API and is
statically using the generic netlink multicast group 1, even
if that group belongs to somebody else (which it invariably
will, since it's not reserved.)

Make the drop monitor code use the proper APIs to reserve a
group ID, but also reserve the group id 1 in generic netlink
code to preserve the userspace API. Since drop monitor can
be a module, don't clear the bit for it on unregistration.

Cc: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/core/drop_monitor.c | 13 ++++++++++++-
 net/netlink/genetlink.c | 13 ++++++++++---
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
index 0efc502..46ee488 100644
--- a/net/core/drop_monitor.c
+++ b/net/core/drop_monitor.c
@@ -106,6 +106,10 @@ static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data)
 	return skb;
 }
 
+static struct genl_multicast_group dm_mcgrp = {
+	.name = "events",
+};
+
 static void send_dm_alert(struct work_struct *work)
 {
 	struct sk_buff *skb;
@@ -116,7 +120,7 @@ static void send_dm_alert(struct work_struct *work)
 	skb = reset_per_cpu_data(data);
 
 	if (skb)
-		genlmsg_multicast(skb, 0, NET_DM_GRP_ALERT, GFP_KERNEL);
+		genlmsg_multicast(skb, 0, dm_mcgrp.id, GFP_KERNEL);
 }
 
 /*
@@ -371,6 +375,13 @@ static int __init init_net_drop_monitor(void)
 		return rc;
 	}
 
+	rc = genl_register_mc_group(&net_drop_monitor_family, &dm_mcgrp);
+	if (rc) {
+		pr_err("Failed to register drop monitor mcast group\n");
+		goto out_unreg;
+	}
+	WARN_ON(dm_mcgrp.id != NET_DM_GRP_ALERT);
+
 	rc = register_netdevice_notifier(&dropmon_net_notifier);
 	if (rc < 0) {
 		pr_crit("Failed to register netdevice notifier\n");
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 2b57aee..8a2ed2c 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -65,8 +65,12 @@ static struct list_head family_ht[GENL_FAM_TAB_SIZE];
  * To avoid an allocation at boot of just one unsigned long,
  * declare it global instead.
  * Bit 0 is marked as already used since group 0 is invalid.
+ * Bit 1 is marked as already used since the drop-monitor code
+ * abuses the API and thinks it can statically use group 1.
+ * That group will typically conflict with other groups that
+ * any proper users use.
  */
-static unsigned long mc_group_start = 0x1;
+static unsigned long mc_group_start = 0x3;
 static unsigned long *mc_groups = &mc_group_start;
 static unsigned long mc_groups_longs = 1;
 
@@ -160,9 +164,11 @@ int genl_register_mc_group(struct genl_family *family,
 
 	genl_lock_all();
 
-	/* special-case our own group */
+	/* special-case our own group and hacks */
 	if (grp == &notify_grp)
 		id = GENL_ID_CTRL;
+	else if (strcmp(family->name, "NET_DM") == 0)
+		id = 1;
 	else
 		id = find_first_zero_bit(mc_groups,
 					 mc_groups_longs * BITS_PER_LONG);
@@ -245,7 +251,8 @@ static void __genl_unregister_mc_group(struct genl_family *family,
 	rcu_read_unlock();
 	netlink_table_ungrab();
 
-	clear_bit(grp->id, mc_groups);
+	if (grp->id != 1)
+		clear_bit(grp->id, mc_groups);
 	list_del(&grp->list);
 	genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
 	grp->id = 0;
-- 
1.8.4.rc3

^ permalink raw reply related

* [RFC 7/8] genetlink: pass family to genlmsg_multicast() and friends
From: Johannes Berg @ 2013-11-16 17:03 UTC (permalink / raw)
  To: netdev; +Cc: Johannes Berg
In-Reply-To: <1384621429-24543-1-git-send-email-johannes@sipsolutions.net>

From: Johannes Berg <johannes.berg@intel.com>

This doesn't really change anything, but prepares for the
next patch that will change the API to pass the group ID
within the family, rather than the global group ID.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/acpi/event.c            |  3 +-
 drivers/net/team/team.c         |  5 +--
 drivers/scsi/pmcraid.c          |  3 +-
 drivers/thermal/thermal_core.c  |  3 +-
 fs/quota/netlink.c              |  2 +-
 include/linux/genl_magic_func.h |  3 +-
 include/net/genetlink.h         | 18 ++++++++---
 net/core/drop_monitor.c         |  3 +-
 net/hsr/hsr_netlink.c           |  6 ++--
 net/ieee802154/netlink.c        |  2 +-
 net/netlink/genetlink.c         | 12 ++++---
 net/nfc/netlink.c               | 39 +++++++++++++++--------
 net/openvswitch/datapath.c      | 31 +++++++++++-------
 net/openvswitch/datapath.h      |  1 +
 net/openvswitch/dp_notify.c     |  3 +-
 net/wimax/op-msg.c              |  3 +-
 net/wimax/stack.c               |  3 +-
 net/wireless/nl80211.c          | 70 ++++++++++++++++++++---------------------
 18 files changed, 127 insertions(+), 83 deletions(-)

diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 8247fcd..68a8755 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -146,7 +146,8 @@ int acpi_bus_generate_netlink_event(const char *device_class,
 		return result;
 	}
 
-	genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&acpi_event_genl_family,
+			  skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
 	return 0;
 }
 
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index f55758b..2721e29 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -2677,8 +2677,9 @@ static struct genl_multicast_group team_change_event_mcgrp = {
 static int team_nl_send_multicast(struct sk_buff *skb,
 				  struct team *team, u32 portid)
 {
-	return genlmsg_multicast_netns(dev_net(team->dev), skb, 0,
-				       team_change_event_mcgrp.id, GFP_KERNEL);
+	return genlmsg_multicast_netns(&team_nl_family, dev_net(team->dev),
+				       skb, 0, team_change_event_mcgrp.id,
+				       GFP_KERNEL);
 }
 
 static int team_nl_send_event_options_get(struct team *team,
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 1eb7b028..2775441 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -1512,7 +1512,8 @@ static int pmcraid_notify_aen(
 	}
 
 	result =
-		genlmsg_multicast(skb, 0, pmcraid_event_family.id, GFP_ATOMIC);
+		genlmsg_multicast(&pmcraid_event_family, skb, 0,
+				  pmcraid_event_family.id, GFP_ATOMIC);
 
 	/* If there are no listeners, genlmsg_multicast may return non-zero
 	 * value.
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 4962a6a..2570a94 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1675,7 +1675,8 @@ int thermal_generate_netlink_event(struct thermal_zone_device *tz,
 		return result;
 	}
 
-	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
+	result = genlmsg_multicast(&thermal_event_genl_family, skb, 0,
+				   thermal_event_mcgrp.id, GFP_ATOMIC);
 	if (result)
 		dev_err(&tz->device, "Failed to send netlink event:%d", result);
 
diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
index b261ce4..2e2220d 100644
--- a/fs/quota/netlink.c
+++ b/fs/quota/netlink.c
@@ -88,7 +88,7 @@ void quota_send_warning(struct kqid qid, dev_t dev,
 		goto attr_err_out;
 	genlmsg_end(skb, msg_head);
 
-	genlmsg_multicast(skb, 0, quota_mcgrp.id, GFP_NOFS);
+	genlmsg_multicast(&quota_genl_family, skb, 0, quota_mcgrp.id, GFP_NOFS);
 	return;
 attr_err_out:
 	printk(KERN_ERR "VFS: Not enough space to compose quota message!\n");
diff --git a/include/linux/genl_magic_func.h b/include/linux/genl_magic_func.h
index 4708603..5b9b8ae 100644
--- a/include/linux/genl_magic_func.h
+++ b/include/linux/genl_magic_func.h
@@ -286,7 +286,8 @@ static int CONCAT_(GENL_MAGIC_FAMILY, _genl_multicast_ ## group)(	\
 		CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group).id;	\
 	if (!group_id)							\
 		return -EINVAL;						\
-	return genlmsg_multicast(skb, 0, group_id, flags);		\
+	return genlmsg_multicast(&ZZZ_genl_family, skb, 0,		\
+				 group_id, flags);			\
 }
 
 #include GENL_MAGIC_INCLUDE_FILE
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index d8a8b1f..3c7511b 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -166,7 +166,8 @@ static inline int _genl_register_family_with_ops(struct genl_family *family,
 int genl_unregister_family(struct genl_family *family);
 int genl_register_mc_group(struct genl_family *family,
 			   struct genl_multicast_group *grp);
-void genl_notify(struct sk_buff *skb, struct net *net, u32 portid,
+void genl_notify(struct genl_family *family,
+		 struct sk_buff *skb, struct net *net, u32 portid,
 		 u32 group, struct nlmsghdr *nlh, gfp_t flags);
 
 void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
@@ -246,13 +247,15 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
 
 /**
  * genlmsg_multicast_netns - multicast a netlink message to a specific netns
+ * @family: the generic netlink family
  * @net: the net namespace
  * @skb: netlink message as socket buffer
  * @portid: own netlink portid to avoid sending to yourself
  * @group: multicast group id
  * @flags: allocation flags
  */
-static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb,
+static inline int genlmsg_multicast_netns(struct genl_family *family,
+					  struct net *net, struct sk_buff *skb,
 					  u32 portid, unsigned int group, gfp_t flags)
 {
 	return nlmsg_multicast(net->genl_sock, skb, portid, group, flags);
@@ -260,19 +263,23 @@ static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb,
 
 /**
  * genlmsg_multicast - multicast a netlink message to the default netns
+ * @family: the generic netlink family
  * @skb: netlink message as socket buffer
  * @portid: own netlink portid to avoid sending to yourself
  * @group: multicast group id
  * @flags: allocation flags
  */
-static inline int genlmsg_multicast(struct sk_buff *skb, u32 portid,
+static inline int genlmsg_multicast(struct genl_family *family,
+				    struct sk_buff *skb, u32 portid,
 				    unsigned int group, gfp_t flags)
 {
-	return genlmsg_multicast_netns(&init_net, skb, portid, group, flags);
+	return genlmsg_multicast_netns(family, &init_net, skb,
+				       portid, group, flags);
 }
 
 /**
  * genlmsg_multicast_allns - multicast a netlink message to all net namespaces
+ * @family: the generic netlink family
  * @skb: netlink message as socket buffer
  * @portid: own netlink portid to avoid sending to yourself
  * @group: multicast group id
@@ -280,7 +287,8 @@ static inline int genlmsg_multicast(struct sk_buff *skb, u32 portid,
  *
  * This function must hold the RTNL or rcu_read_lock().
  */
-int genlmsg_multicast_allns(struct sk_buff *skb, u32 portid,
+int genlmsg_multicast_allns(struct genl_family *family,
+			    struct sk_buff *skb, u32 portid,
 			    unsigned int group, gfp_t flags);
 
 /**
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
index 46ee488..1eab1dc 100644
--- a/net/core/drop_monitor.c
+++ b/net/core/drop_monitor.c
@@ -120,7 +120,8 @@ static void send_dm_alert(struct work_struct *work)
 	skb = reset_per_cpu_data(data);
 
 	if (skb)
-		genlmsg_multicast(skb, 0, dm_mcgrp.id, GFP_KERNEL);
+		genlmsg_multicast(&net_drop_monitor_family, skb, 0,
+				  dm_mcgrp.id, GFP_KERNEL);
 }
 
 /*
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
index 908e335..0009416 100644
--- a/net/hsr/hsr_netlink.c
+++ b/net/hsr/hsr_netlink.c
@@ -129,7 +129,8 @@ void hsr_nl_ringerror(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN],
 		goto nla_put_failure;
 
 	genlmsg_end(skb, msg_head);
-	genlmsg_multicast(skb, 0, hsr_network_genl_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&hsr_genl_family, skb, 0,
+			  hsr_network_genl_mcgrp.id, GFP_ATOMIC);
 
 	return;
 
@@ -163,7 +164,8 @@ void hsr_nl_nodedown(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN])
 		goto nla_put_failure;
 
 	genlmsg_end(skb, msg_head);
-	genlmsg_multicast(skb, 0, hsr_network_genl_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&hsr_genl_family, skb, 0,
+			  hsr_network_genl_mcgrp.id, GFP_ATOMIC);
 
 	return;
 
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index 1a81709..5172f46 100644
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -70,7 +70,7 @@ int ieee802154_nl_mcast(struct sk_buff *msg, unsigned int group)
 	if (genlmsg_end(msg, hdr) < 0)
 		goto out;
 
-	return genlmsg_multicast(msg, 0, group, GFP_ATOMIC);
+	return genlmsg_multicast(&nl802154_family, msg, 0, group, GFP_ATOMIC);
 out:
 	nlmsg_free(msg);
 	return -ENOBUFS;
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 5e81562..0e1e1fb 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -883,11 +883,12 @@ static int genl_ctrl_event(int event, struct genl_family *family,
 		return PTR_ERR(msg);
 
 	if (!family->netnsok) {
-		genlmsg_multicast_netns(&init_net, msg, 0,
+		genlmsg_multicast_netns(&genl_ctrl, &init_net, msg, 0,
 					GENL_ID_CTRL, GFP_KERNEL);
 	} else {
 		rcu_read_lock();
-		genlmsg_multicast_allns(msg, 0, GENL_ID_CTRL, GFP_ATOMIC);
+		genlmsg_multicast_allns(&genl_ctrl, msg, 0,
+					GENL_ID_CTRL, GFP_ATOMIC);
 		rcu_read_unlock();
 	}
 
@@ -993,14 +994,15 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group,
 	return err;
 }
 
-int genlmsg_multicast_allns(struct sk_buff *skb, u32 portid, unsigned int group,
-			    gfp_t flags)
+int genlmsg_multicast_allns(struct genl_family *family, struct sk_buff *skb,
+			    u32 portid, unsigned int group, gfp_t flags)
 {
 	return genlmsg_mcast(skb, portid, group, flags);
 }
 EXPORT_SYMBOL(genlmsg_multicast_allns);
 
-void genl_notify(struct sk_buff *skb, struct net *net, u32 portid, u32 group,
+void genl_notify(struct genl_family *family,
+		 struct sk_buff *skb, struct net *net, u32 portid, u32 group,
 		 struct nlmsghdr *nlh, gfp_t flags)
 {
 	struct sock *sk = net->genl_sock;
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index fe6760d..3092df31 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -194,7 +194,8 @@ int nfc_genl_targets_found(struct nfc_dev *dev)
 
 	genlmsg_end(msg, hdr);
 
-	return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
+	return genlmsg_multicast(&nfc_genl_family, msg, 0,
+				 nfc_genl_event_mcgrp.id, GFP_ATOMIC);
 
 nla_put_failure:
 	genlmsg_cancel(msg, hdr);
@@ -223,7 +224,8 @@ int nfc_genl_target_lost(struct nfc_dev *dev, u32 target_idx)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0,
+			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
 
 	return 0;
 
@@ -255,7 +257,8 @@ int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0,
+			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
 
 	return 0;
 
@@ -285,7 +288,8 @@ int nfc_genl_tm_deactivated(struct nfc_dev *dev)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0,
+			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
 
 	return 0;
 
@@ -318,7 +322,8 @@ int nfc_genl_device_added(struct nfc_dev *dev)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0,
+			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
 
 	return 0;
 
@@ -348,7 +353,8 @@ int nfc_genl_device_removed(struct nfc_dev *dev)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0,
+			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
 
 	return 0;
 
@@ -414,7 +420,8 @@ int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list)
 
 	genlmsg_end(msg, hdr);
 
-	return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
+	return genlmsg_multicast(&nfc_genl_family, msg, 0,
+				 nfc_genl_event_mcgrp.id, GFP_ATOMIC);
 
 nla_put_failure:
 	genlmsg_cancel(msg, hdr);
@@ -448,7 +455,8 @@ int nfc_genl_se_added(struct nfc_dev *dev, u32 se_idx, u16 type)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0,
+			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
 
 	return 0;
 
@@ -479,7 +487,8 @@ int nfc_genl_se_removed(struct nfc_dev *dev, u32 se_idx)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0,
+			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
 
 	return 0;
 
@@ -600,7 +609,8 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
 
 	dev->dep_link_up = true;
 
-	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&nfc_genl_family, msg, 0,
+			  nfc_genl_event_mcgrp.id, GFP_ATOMIC);
 
 	return 0;
 
@@ -632,7 +642,8 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&nfc_genl_family, msg, 0,
+			  nfc_genl_event_mcgrp.id, GFP_ATOMIC);
 
 	return 0;
 
@@ -1137,7 +1148,8 @@ int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0,
+			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
 
 	return 0;
 
@@ -1308,7 +1320,8 @@ static void se_io_cb(void *context, u8 *apdu, size_t apdu_len, int err)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0,
+			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
 
 	kfree(ctx);
 
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 8ec8b73..1de9446 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -61,10 +61,11 @@
 
 int ovs_net_id __read_mostly;
 
-static void ovs_notify(struct sk_buff *skb, struct genl_info *info,
+static void ovs_notify(struct genl_family *family,
+		       struct sk_buff *skb, struct genl_info *info,
 		       struct genl_multicast_group *grp)
 {
-	genl_notify(skb, genl_info_net(info), info->snd_portid,
+	genl_notify(family, skb, genl_info_net(info), info->snd_portid,
 		    grp->id, info->nlhdr, GFP_KERNEL);
 }
 
@@ -877,7 +878,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 	ovs_unlock();
 
 	if (!IS_ERR(reply))
-		ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
+		ovs_notify(&dp_flow_genl_family, reply, info,
+			   &ovs_dp_flow_multicast_group);
 	else
 		netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
 				ovs_dp_flow_multicast_group.id, PTR_ERR(reply));
@@ -990,7 +992,8 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	ovs_flow_free(flow, true);
 	ovs_unlock();
 
-	ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
+	ovs_notify(&dp_flow_genl_family, reply, info,
+		   &ovs_dp_flow_multicast_group);
 	return 0;
 unlock:
 	ovs_unlock();
@@ -1237,7 +1240,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
 
 	ovs_unlock();
 
-	ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
+	ovs_notify(&dp_datapath_genl_family, reply, info,
+		   &ovs_dp_datapath_multicast_group);
 	return 0;
 
 err_destroy_local_port:
@@ -1302,7 +1306,8 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	__dp_destroy(dp);
 	ovs_unlock();
 
-	ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
+	ovs_notify(&dp_datapath_genl_family, reply, info,
+		   &ovs_dp_datapath_multicast_group);
 
 	return 0;
 unlock:
@@ -1333,7 +1338,8 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
 	}
 
 	ovs_unlock();
-	ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
+	ovs_notify(&dp_datapath_genl_family, reply, info,
+		   &ovs_dp_datapath_multicast_group);
 
 	return 0;
 unlock:
@@ -1425,7 +1431,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
 	[OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },
 };
 
-static struct genl_family dp_vport_genl_family = {
+struct genl_family dp_vport_genl_family = {
 	.id = GENL_ID_GENERATE,
 	.hdrsize = sizeof(struct ovs_header),
 	.name = OVS_VPORT_FAMILY,
@@ -1595,7 +1601,8 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
 		goto exit_unlock;
 	}
 
-	ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
+	ovs_notify(&dp_vport_genl_family, reply, info,
+		   &ovs_dp_vport_multicast_group);
 
 exit_unlock:
 	ovs_unlock();
@@ -1642,7 +1649,8 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
 	BUG_ON(err < 0);
 
 	ovs_unlock();
-	ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
+	ovs_notify(&dp_vport_genl_family, reply, info,
+		   &ovs_dp_vport_multicast_group);
 	return 0;
 
 exit_free:
@@ -1679,7 +1687,8 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	err = 0;
 	ovs_dp_detach_port(vport);
 
-	ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
+	ovs_notify(&dp_vport_genl_family, reply, info,
+		   &ovs_dp_vport_multicast_group);
 
 exit_unlock:
 	ovs_unlock();
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index d3d14a58..4067ea4 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -177,6 +177,7 @@ static inline struct vport *ovs_vport_ovsl(const struct datapath *dp, int port_n
 }
 
 extern struct notifier_block ovs_dp_device_notifier;
+extern struct genl_family dp_vport_genl_family;
 extern struct genl_multicast_group ovs_dp_vport_multicast_group;
 
 void ovs_dp_process_received_packet(struct vport *, struct sk_buff *);
diff --git a/net/openvswitch/dp_notify.c b/net/openvswitch/dp_notify.c
index 5c2dab2..aa29d85 100644
--- a/net/openvswitch/dp_notify.c
+++ b/net/openvswitch/dp_notify.c
@@ -40,7 +40,8 @@ static void dp_detach_port_notify(struct vport *vport)
 		return;
 	}
 
-	genlmsg_multicast_netns(ovs_dp_get_net(dp), notify, 0,
+	genlmsg_multicast_netns(&dp_vport_genl_family,
+				ovs_dp_get_net(dp), notify, 0,
 				ovs_dp_vport_multicast_group.id,
 				GFP_KERNEL);
 }
diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c
index ff19cbe..f37dd3c 100644
--- a/net/wimax/op-msg.c
+++ b/net/wimax/op-msg.c
@@ -279,7 +279,8 @@ int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
 
 	d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size);
 	d_dump(2, dev, msg, size);
-	genlmsg_multicast(skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
+	genlmsg_multicast(&wimax_gnl_family, skb, 0,
+			  wimax_gnl_mcg.id, GFP_KERNEL);
 	d_printf(1, dev, "CTX: genl multicast done\n");
 	return 0;
 }
diff --git a/net/wimax/stack.c b/net/wimax/stack.c
index 6328afe..1888874 100644
--- a/net/wimax/stack.c
+++ b/net/wimax/stack.c
@@ -177,7 +177,8 @@ int wimax_gnl_re_state_change_send(
 		goto out;
 	}
 	genlmsg_end(report_skb, header);
-	genlmsg_multicast(report_skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
+	genlmsg_multicast(&wimax_gnl_family, report_skb, 0,
+			  wimax_gnl_mcg.id, GFP_KERNEL);
 out:
 	d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n",
 		wimax_dev, report_skb, result);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 1b6c5dd..f20edfd 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6868,7 +6868,7 @@ void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
 
 	nla_nest_end(skb, data);
 	genlmsg_end(skb, hdr);
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
 				nl80211_testmode_mcgrp.id, gfp);
 }
 EXPORT_SYMBOL(cfg80211_testmode_event);
@@ -9597,7 +9597,7 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
 		return;
 	}
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_config_mcgrp.id, GFP_KERNEL);
 }
 
@@ -9707,7 +9707,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
 		return;
 	}
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_scan_mcgrp.id, GFP_KERNEL);
 }
 
@@ -9726,7 +9726,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
 		return;
 	}
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_scan_mcgrp.id, GFP_KERNEL);
 }
 
@@ -9745,7 +9745,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
 		return;
 	}
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_scan_mcgrp.id, GFP_KERNEL);
 }
 
@@ -9764,7 +9764,7 @@ void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
 		return;
 	}
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_scan_mcgrp.id, GFP_KERNEL);
 }
 
@@ -9782,7 +9782,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
 		return;
 	}
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_scan_mcgrp.id, GFP_KERNEL);
 }
 
@@ -9837,8 +9837,8 @@ void nl80211_send_reg_change_event(struct regulatory_request *request)
 	genlmsg_end(msg, hdr);
 
 	rcu_read_lock();
-	genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
-				GFP_ATOMIC);
+	genlmsg_multicast_allns(&nl80211_fam, msg, 0,
+				nl80211_regulatory_mcgrp.id, GFP_ATOMIC);
 	rcu_read_unlock();
 
 	return;
@@ -9873,7 +9873,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -9961,7 +9961,7 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10017,7 +10017,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10056,7 +10056,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10094,7 +10094,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, GFP_KERNEL);
 	return;
 
@@ -10128,7 +10128,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10169,7 +10169,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10208,7 +10208,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10261,8 +10261,8 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
 	genlmsg_end(msg, hdr);
 
 	rcu_read_lock();
-	genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
-				GFP_ATOMIC);
+	genlmsg_multicast_allns(&nl80211_fam, msg, 0,
+				nl80211_regulatory_mcgrp.id, GFP_ATOMIC);
 	rcu_read_unlock();
 
 	return;
@@ -10307,7 +10307,7 @@ static void nl80211_send_remain_on_chan_event(
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10362,7 +10362,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
 		return;
 	}
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 }
 EXPORT_SYMBOL(cfg80211_new_sta);
@@ -10392,7 +10392,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10428,7 +10428,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10590,7 +10590,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10639,7 +10639,7 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10684,7 +10684,7 @@ static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10742,7 +10742,7 @@ nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10789,7 +10789,7 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10866,7 +10866,7 @@ void cfg80211_cqm_txe_notify(struct net_device *dev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10915,7 +10915,7 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -10962,7 +10962,7 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -11002,7 +11002,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -11154,7 +11154,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -11196,7 +11196,7 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, gfp);
 	return;
 
@@ -11279,7 +11279,7 @@ void cfg80211_ft_event(struct net_device *netdev,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
 				nl80211_mlme_mcgrp.id, GFP_KERNEL);
 }
 EXPORT_SYMBOL(cfg80211_ft_event);
-- 
1.8.4.rc3

^ permalink raw reply related

* [RFC 8/8] genetlink: make multicast groups const, prevent abuse
From: Johannes Berg @ 2013-11-16 17:03 UTC (permalink / raw)
  To: netdev; +Cc: Johannes Berg
In-Reply-To: <1384621429-24543-1-git-send-email-johannes@sipsolutions.net>

From: Johannes Berg <johannes.berg@intel.com>

Register generic netlink multicast groups as an array with
the family and give them contiguous group IDs. Then instead
of passing the global group ID to the various functions that
send messages, pass the ID relative to the family - for most
families that's just 0 because the only have one group.

This avoids the list_head and ID in each group, adding a new
field for the mcast group ID offset to the family.

At the same time, this allows us to prevent abusing groups
again like the quota and dropmon code did, since we can now
check that a family only uses a group it owns.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/acpi/event.c            |  26 ++--
 drivers/net/team/team.c         |  25 +---
 drivers/thermal/thermal_core.c  |  24 ++--
 fs/quota/netlink.c              |  15 ++-
 include/linux/genl_magic_func.h |  49 +++-----
 include/net/genetlink.h         |  47 ++++---
 net/core/drop_monitor.c         |  18 +--
 net/hsr/hsr_netlink.c           |  19 +--
 net/ieee802154/ieee802154.h     |   6 +-
 net/ieee802154/netlink.c        |  26 ++--
 net/ieee802154/nl-mac.c         |  22 ++--
 net/netlink/genetlink.c         | 273 ++++++++++++++++++++++++----------------
 net/nfc/netlink.c               |  51 +++-----
 net/openvswitch/datapath.c      |  43 +++----
 net/openvswitch/dp_notify.c     |   5 +-
 net/wimax/op-msg.c              |   3 +-
 net/wimax/stack.c               |  20 ++-
 net/wimax/wimax-internal.h      |   1 -
 net/wireless/nl80211.c          | 129 ++++++++-----------
 19 files changed, 371 insertions(+), 431 deletions(-)

diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 68a8755..aeb5aa6 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -78,15 +78,17 @@ enum {
 #define ACPI_GENL_VERSION		0x01
 #define ACPI_GENL_MCAST_GROUP_NAME 	"acpi_mc_group"
 
+static const struct genl_multicast_group acpi_event_mcgrps[] = {
+	{ .name = ACPI_GENL_MCAST_GROUP_NAME, },
+};
+
 static struct genl_family acpi_event_genl_family = {
 	.id = GENL_ID_GENERATE,
 	.name = ACPI_GENL_FAMILY_NAME,
 	.version = ACPI_GENL_VERSION,
 	.maxattr = ACPI_GENL_ATTR_MAX,
-};
-
-static struct genl_multicast_group acpi_event_mcgrp = {
-	.name = ACPI_GENL_MCAST_GROUP_NAME,
+	.mcgrps = acpi_event_mcgrps,
+	.n_mcgrps = ARRAY_SIZE(acpi_event_mcgrps),
 };
 
 int acpi_bus_generate_netlink_event(const char *device_class,
@@ -146,8 +148,7 @@ int acpi_bus_generate_netlink_event(const char *device_class,
 		return result;
 	}
 
-	genlmsg_multicast(&acpi_event_genl_family,
-			  skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&acpi_event_genl_family, skb, 0, 0, GFP_ATOMIC);
 	return 0;
 }
 
@@ -155,18 +156,7 @@ EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
 
 static int acpi_event_genetlink_init(void)
 {
-	int result;
-
-	result = genl_register_family(&acpi_event_genl_family);
-	if (result)
-		return result;
-
-	result = genl_register_mc_group(&acpi_event_genl_family,
-					&acpi_event_mcgrp);
-	if (result)
-		genl_unregister_family(&acpi_event_genl_family);
-
-	return result;
+	return genl_register_family(&acpi_event_genl_family);
 }
 
 #else
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 2721e29..0715de5 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -2670,16 +2670,15 @@ static const struct genl_ops team_nl_ops[] = {
 	},
 };
 
-static struct genl_multicast_group team_change_event_mcgrp = {
-	.name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME,
+static const struct genl_multicast_group team_nl_mcgrps[] = {
+	{ .name = TEAM_GENL_CHANGE_EVENT_MC_GRP_NAME, },
 };
 
 static int team_nl_send_multicast(struct sk_buff *skb,
 				  struct team *team, u32 portid)
 {
 	return genlmsg_multicast_netns(&team_nl_family, dev_net(team->dev),
-				       skb, 0, team_change_event_mcgrp.id,
-				       GFP_KERNEL);
+				       skb, 0, 0, GFP_KERNEL);
 }
 
 static int team_nl_send_event_options_get(struct team *team,
@@ -2698,22 +2697,8 @@ static int team_nl_send_event_port_get(struct team *team,
 
 static int team_nl_init(void)
 {
-	int err;
-
-	err = genl_register_family_with_ops(&team_nl_family, team_nl_ops);
-	if (err)
-		return err;
-
-	err = genl_register_mc_group(&team_nl_family, &team_change_event_mcgrp);
-	if (err)
-		goto err_change_event_grp_reg;
-
-	return 0;
-
-err_change_event_grp_reg:
-	genl_unregister_family(&team_nl_family);
-
-	return err;
+	return genl_register_family_with_ops_groups(&team_nl_family, team_nl_ops,
+						    team_nl_mcgrps);
 }
 
 static void team_nl_fini(void)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 2570a94..19edd61 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1606,15 +1606,17 @@ exit:
 EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name);
 
 #ifdef CONFIG_NET
+static const struct genl_multicast_group thermal_event_mcgrps[] = {
+	{ .name = THERMAL_GENL_MCAST_GROUP_NAME, },
+};
+
 static struct genl_family thermal_event_genl_family = {
 	.id = GENL_ID_GENERATE,
 	.name = THERMAL_GENL_FAMILY_NAME,
 	.version = THERMAL_GENL_VERSION,
 	.maxattr = THERMAL_GENL_ATTR_MAX,
-};
-
-static struct genl_multicast_group thermal_event_mcgrp = {
-	.name = THERMAL_GENL_MCAST_GROUP_NAME,
+	.mcgrps = thermal_event_mcgrps,
+	.n_mcgrps = ARRAY_SIZE(thermal_event_mcgrps),
 };
 
 int thermal_generate_netlink_event(struct thermal_zone_device *tz,
@@ -1676,7 +1678,7 @@ int thermal_generate_netlink_event(struct thermal_zone_device *tz,
 	}
 
 	result = genlmsg_multicast(&thermal_event_genl_family, skb, 0,
-				   thermal_event_mcgrp.id, GFP_ATOMIC);
+				   0, GFP_ATOMIC);
 	if (result)
 		dev_err(&tz->device, "Failed to send netlink event:%d", result);
 
@@ -1686,17 +1688,7 @@ EXPORT_SYMBOL_GPL(thermal_generate_netlink_event);
 
 static int genetlink_init(void)
 {
-	int result;
-
-	result = genl_register_family(&thermal_event_genl_family);
-	if (result)
-		return result;
-
-	result = genl_register_mc_group(&thermal_event_genl_family,
-					&thermal_event_mcgrp);
-	if (result)
-		genl_unregister_family(&thermal_event_genl_family);
-	return result;
+	return genl_register_family(&thermal_event_genl_family);
 }
 
 static void genetlink_exit(void)
diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
index 2e2220d..b8ae6f0 100644
--- a/fs/quota/netlink.c
+++ b/fs/quota/netlink.c
@@ -9,6 +9,10 @@
 #include <net/netlink.h>
 #include <net/genetlink.h>
 
+static const struct genl_multicast_group quota_mcgrps[] = {
+	{ .name = "VFS_DQUOT", /* not really used */ },
+};
+
 /* Netlink family structure for quota */
 static struct genl_family quota_genl_family = {
 	/*
@@ -22,10 +26,8 @@ static struct genl_family quota_genl_family = {
 	.name = "VFS_DQUOT",
 	.version = 1,
 	.maxattr = QUOTA_NL_A_MAX,
-};
-
-static struct genl_multicast_group quota_mcgrp = {
-	.name = "VFS_DQUOT", /* not really used */
+	.mcgrps = quota_mcgrps,
+	.n_mcgrps = ARRAY_SIZE(quota_mcgrps),
 };
 
 /**
@@ -88,7 +90,7 @@ void quota_send_warning(struct kqid qid, dev_t dev,
 		goto attr_err_out;
 	genlmsg_end(skb, msg_head);
 
-	genlmsg_multicast(&quota_genl_family, skb, 0, quota_mcgrp.id, GFP_NOFS);
+	genlmsg_multicast(&quota_genl_family, skb, 0, 0, GFP_NOFS);
 	return;
 attr_err_out:
 	printk(KERN_ERR "VFS: Not enough space to compose quota message!\n");
@@ -102,9 +104,6 @@ static int __init quota_init(void)
 	if (genl_register_family(&quota_genl_family) != 0)
 		printk(KERN_ERR
 		       "VFS: Failed to create quota netlink interface.\n");
-	if (genl_register_mc_group(&quota_genl_family, &quota_mcgrp))
-		printk(KERN_ERR
-		       "VFS: Failed to register quota mcast group.\n");
 	return 0;
 };
 
diff --git a/include/linux/genl_magic_func.h b/include/linux/genl_magic_func.h
index 5b9b8ae..c0894dd 100644
--- a/include/linux/genl_magic_func.h
+++ b/include/linux/genl_magic_func.h
@@ -273,49 +273,40 @@ static struct genl_family ZZZ_genl_family __read_mostly = {
  * Magic: define multicast groups
  * Magic: define multicast group registration helper
  */
+#define ZZZ_genl_mcgrps		CONCAT_(GENL_MAGIC_FAMILY, _genl_mcgrps)
+static const struct genl_multicast_group ZZZ_genl_mcgrps[] = {
+#undef GENL_mc_group
+#define GENL_mc_group(group) { .name = #group, },
+#include GENL_MAGIC_INCLUDE_FILE
+};
+
+enum CONCAT_(GENL_MAGIC_FAMILY, group_ids) {
+#undef GENL_mc_group
+#define GENL_mc_group(group) CONCAT_(GENL_MAGIC_FAMILY, _group_ ## group),
+#include GENL_MAGIC_INCLUDE_FILE
+};
+
 #undef GENL_mc_group
 #define GENL_mc_group(group)						\
-static struct genl_multicast_group					\
-CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group) __read_mostly = {		\
-	.name = #group,							\
-};									\
 static int CONCAT_(GENL_MAGIC_FAMILY, _genl_multicast_ ## group)(	\
 	struct sk_buff *skb, gfp_t flags)				\
 {									\
 	unsigned int group_id =						\
-		CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group).id;	\
-	if (!group_id)							\
-		return -EINVAL;						\
+		CONCAT_(GENL_MAGIC_FAMILY, _group_ ## group);		\
 	return genlmsg_multicast(&ZZZ_genl_family, skb, 0,		\
 				 group_id, flags);			\
 }
 
 #include GENL_MAGIC_INCLUDE_FILE
 
-int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void)
-{
-	int err = genl_register_family_with_ops(&ZZZ_genl_family, ZZZ_genl_ops);
-	if (err)
-		return err;
-#undef GENL_mc_group
-#define GENL_mc_group(group)						\
-	err = genl_register_mc_group(&ZZZ_genl_family,			\
-		&CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group));		\
-	if (err)							\
-		goto fail;						\
-	else								\
-		pr_info("%s: mcg %s: %u\n", #group,			\
-			__stringify(GENL_MAGIC_FAMILY),			\
-			CONCAT_(GENL_MAGIC_FAMILY, _mcg_ ## group).id);
-
-#include GENL_MAGIC_INCLUDE_FILE
-
 #undef GENL_mc_group
 #define GENL_mc_group(group)
-	return 0;
-fail:
-	genl_unregister_family(&ZZZ_genl_family);
-	return err;
+
+int CONCAT_(GENL_MAGIC_FAMILY, _genl_register)(void)
+{
+	return genl_register_family_with_ops_groups(&ZZZ_genl_family,	\
+						    ZZZ_genl_ops,	\
+						    ZZZ_genl_mcgrps);
 }
 
 void CONCAT_(GENL_MAGIC_FAMILY, _genl_unregister)(void)
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index 3c7511b..dca75ad 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -10,14 +10,9 @@
 /**
  * struct genl_multicast_group - generic netlink multicast group
  * @name: name of the multicast group, names are per-family
- * @id: multicast group ID, assigned by the core, to use with
- *      genlmsg_multicast().
- * @list: list entry for linking
  */
 struct genl_multicast_group {
-	struct list_head	list;		/* private */
 	char			name[GENL_NAMSIZ];
-	u32			id;
 };
 
 struct genl_ops;
@@ -38,7 +33,9 @@ struct genl_info;
  *	undo operations done by pre_doit, for example release locks
  * @attrbuf: buffer to store parsed attributes
  * @family_list: family list
- * @mcast_groups: multicast groups list
+ * @mcgrps: multicast groups used by this family (private)
+ * @n_mcgrps: number of multicast groups (private)
+ * @mcgrp_offset: starting number of multicast group IDs in this family
  * @ops: the operations supported by this family (private)
  * @n_ops: number of operations supported by this family (private)
  */
@@ -58,9 +55,11 @@ struct genl_family {
 					     struct genl_info *info);
 	struct nlattr **	attrbuf;	/* private */
 	const struct genl_ops *	ops;		/* private */
+	const struct genl_multicast_group *mcgrps; /* private */
 	unsigned int		n_ops;		/* private */
+	unsigned int		n_mcgrps;	/* private */
+	unsigned int		mcgrp_offset;	/* private */
 	struct list_head	family_list;	/* private */
-	struct list_head	mcast_groups;	/* private */
 	struct module		*module;
 };
 
@@ -150,22 +149,30 @@ static inline int genl_register_family(struct genl_family *family)
  *
  * Return 0 on success or a negative error code.
  */
-static inline int _genl_register_family_with_ops(struct genl_family *family,
-						 const struct genl_ops *ops,
-						 size_t n_ops)
+static inline int
+_genl_register_family_with_ops_grps(struct genl_family *family,
+				    const struct genl_ops *ops, size_t n_ops,
+				    const struct genl_multicast_group *mcgrps,
+				    size_t n_mcgrps)
 {
 	family->module = THIS_MODULE;
 	family->ops = ops;
 	family->n_ops = n_ops;
+	family->mcgrps = mcgrps;
+	family->n_mcgrps = n_mcgrps;
 	return __genl_register_family(family);
 }
 
-#define genl_register_family_with_ops(family, ops)	\
-	_genl_register_family_with_ops((family), (ops), ARRAY_SIZE(ops))
+#define genl_register_family_with_ops(family, ops)			\
+	_genl_register_family_with_ops_grps((family),			\
+					    (ops), ARRAY_SIZE(ops),	\
+					    NULL, 0)
+#define genl_register_family_with_ops_groups(family, ops, grps)	\
+	_genl_register_family_with_ops_grps((family),			\
+					    (ops), ARRAY_SIZE(ops),	\
+					    (grps), ARRAY_SIZE(grps))
 
 int genl_unregister_family(struct genl_family *family);
-int genl_register_mc_group(struct genl_family *family,
-			   struct genl_multicast_group *grp);
 void genl_notify(struct genl_family *family,
 		 struct sk_buff *skb, struct net *net, u32 portid,
 		 u32 group, struct nlmsghdr *nlh, gfp_t flags);
@@ -251,13 +258,16 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
  * @net: the net namespace
  * @skb: netlink message as socket buffer
  * @portid: own netlink portid to avoid sending to yourself
- * @group: multicast group id
+ * @group: offset of multicast group in groups array
  * @flags: allocation flags
  */
 static inline int genlmsg_multicast_netns(struct genl_family *family,
 					  struct net *net, struct sk_buff *skb,
 					  u32 portid, unsigned int group, gfp_t flags)
 {
+	if (group >= family->n_mcgrps)
+		return -EINVAL;
+	group = family->mcgrp_offset + group;
 	return nlmsg_multicast(net->genl_sock, skb, portid, group, flags);
 }
 
@@ -266,13 +276,16 @@ static inline int genlmsg_multicast_netns(struct genl_family *family,
  * @family: the generic netlink family
  * @skb: netlink message as socket buffer
  * @portid: own netlink portid to avoid sending to yourself
- * @group: multicast group id
+ * @group: offset of multicast group in groups array
  * @flags: allocation flags
  */
 static inline int genlmsg_multicast(struct genl_family *family,
 				    struct sk_buff *skb, u32 portid,
 				    unsigned int group, gfp_t flags)
 {
+	if (group >= family->n_mcgrps)
+		return -EINVAL;
+	group = family->mcgrp_offset + group;
 	return genlmsg_multicast_netns(family, &init_net, skb,
 				       portid, group, flags);
 }
@@ -282,7 +295,7 @@ static inline int genlmsg_multicast(struct genl_family *family,
  * @family: the generic netlink family
  * @skb: netlink message as socket buffer
  * @portid: own netlink portid to avoid sending to yourself
- * @group: multicast group id
+ * @group: offset of multicast group in groups array
  * @flags: allocation flags
  *
  * This function must hold the RTNL or rcu_read_lock().
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
index 1eab1dc..9589718 100644
--- a/net/core/drop_monitor.c
+++ b/net/core/drop_monitor.c
@@ -106,8 +106,8 @@ static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data)
 	return skb;
 }
 
-static struct genl_multicast_group dm_mcgrp = {
-	.name = "events",
+static struct genl_multicast_group dropmon_mcgrps[] = {
+	{ .name = "events", },
 };
 
 static void send_dm_alert(struct work_struct *work)
@@ -121,7 +121,7 @@ static void send_dm_alert(struct work_struct *work)
 
 	if (skb)
 		genlmsg_multicast(&net_drop_monitor_family, skb, 0,
-				  dm_mcgrp.id, GFP_KERNEL);
+				  0, GFP_KERNEL);
 }
 
 /*
@@ -369,19 +369,13 @@ static int __init init_net_drop_monitor(void)
 		return -ENOSPC;
 	}
 
-	rc = genl_register_family_with_ops(&net_drop_monitor_family,
-					   dropmon_ops);
+	rc = genl_register_family_with_ops_groups(&net_drop_monitor_family,
+						  dropmon_ops, dropmon_mcgrps);
 	if (rc) {
 		pr_err("Could not create drop monitor netlink family\n");
 		return rc;
 	}
-
-	rc = genl_register_mc_group(&net_drop_monitor_family, &dm_mcgrp);
-	if (rc) {
-		pr_err("Failed to register drop monitor mcast group\n");
-		goto out_unreg;
-	}
-	WARN_ON(dm_mcgrp.id != NET_DM_GRP_ALERT);
+	WARN_ON(net_drop_monitor_family.mcgrp_offset != NET_DM_GRP_ALERT);
 
 	rc = register_netdevice_notifier(&dropmon_net_notifier);
 	if (rc < 0) {
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c
index 0009416..5325af8 100644
--- a/net/hsr/hsr_netlink.c
+++ b/net/hsr/hsr_netlink.c
@@ -90,8 +90,8 @@ static struct genl_family hsr_genl_family = {
 	.maxattr = HSR_A_MAX,
 };
 
-static struct genl_multicast_group hsr_network_genl_mcgrp = {
-	.name = "hsr-network",
+static const struct genl_multicast_group hsr_mcgrps[] = {
+	{ .name = "hsr-network", },
 };
 
 
@@ -129,8 +129,7 @@ void hsr_nl_ringerror(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN],
 		goto nla_put_failure;
 
 	genlmsg_end(skb, msg_head);
-	genlmsg_multicast(&hsr_genl_family, skb, 0,
-			  hsr_network_genl_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&hsr_genl_family, skb, 0, 0, GFP_ATOMIC);
 
 	return;
 
@@ -164,8 +163,7 @@ void hsr_nl_nodedown(struct hsr_priv *hsr_priv, unsigned char addr[ETH_ALEN])
 		goto nla_put_failure;
 
 	genlmsg_end(skb, msg_head);
-	genlmsg_multicast(&hsr_genl_family, skb, 0,
-			  hsr_network_genl_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&hsr_genl_family, skb, 0, 0, GFP_ATOMIC);
 
 	return;
 
@@ -416,18 +414,13 @@ int __init hsr_netlink_init(void)
 	if (rc)
 		goto fail_rtnl_link_register;
 
-	rc = genl_register_family_with_ops(&hsr_genl_family, hsr_ops);
+	rc = genl_register_family_with_ops_groups(&hsr_genl_family, hsr_ops,
+						  hsr_mcgrps);
 	if (rc)
 		goto fail_genl_register_family;
 
-	rc = genl_register_mc_group(&hsr_genl_family, &hsr_network_genl_mcgrp);
-	if (rc)
-		goto fail_genl_register_mc_group;
-
 	return 0;
 
-fail_genl_register_mc_group:
-	genl_unregister_family(&hsr_genl_family);
 fail_genl_register_family:
 	rtnl_link_unregister(&hsr_link_ops);
 fail_rtnl_link_register:
diff --git a/net/ieee802154/ieee802154.h b/net/ieee802154/ieee802154.h
index 14d5dab..cee4425 100644
--- a/net/ieee802154/ieee802154.h
+++ b/net/ieee802154/ieee802154.h
@@ -54,8 +54,10 @@ int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb);
 int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info);
 int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info);
 
-extern struct genl_multicast_group ieee802154_coord_mcgrp;
-extern struct genl_multicast_group ieee802154_beacon_mcgrp;
+enum ieee802154_mcgrp_ids {
+	IEEE802154_COORD_MCGRP,
+	IEEE802154_BEACON_MCGRP,
+};
 
 int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info);
 int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info);
diff --git a/net/ieee802154/netlink.c b/net/ieee802154/netlink.c
index 5172f46..43f1b2b 100644
--- a/net/ieee802154/netlink.c
+++ b/net/ieee802154/netlink.c
@@ -125,25 +125,17 @@ static const struct genl_ops ieee8021154_ops[] = {
 			ieee802154_dump_iface),
 };
 
-int __init ieee802154_nl_init(void)
-{
-	int rc;
-
-	rc = genl_register_family_with_ops(&nl802154_family, ieee8021154_ops);
-	if (rc)
-		return rc;
+static const struct genl_multicast_group ieee802154_mcgrps[] = {
+	[IEEE802154_COORD_MCGRP] = { .name = IEEE802154_MCAST_COORD_NAME, },
+	[IEEE802154_BEACON_MCGRP] = { .name = IEEE802154_MCAST_BEACON_NAME, },
+};
 
-	rc = genl_register_mc_group(&nl802154_family, &ieee802154_coord_mcgrp);
-	if (rc)
-		goto fail;
 
-	rc = genl_register_mc_group(&nl802154_family, &ieee802154_beacon_mcgrp);
-	if (rc)
-		goto fail;
-	return 0;
-fail:
-	genl_unregister_family(&nl802154_family);
-	return rc;
+int __init ieee802154_nl_init(void)
+{
+	return genl_register_family_with_ops_groups(&nl802154_family,
+						    ieee8021154_ops,
+						    ieee802154_mcgrps);
 }
 
 void __exit ieee802154_nl_exit(void)
diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c
index 28d4930..ba5c1e0 100644
--- a/net/ieee802154/nl-mac.c
+++ b/net/ieee802154/nl-mac.c
@@ -39,14 +39,6 @@
 
 #include "ieee802154.h"
 
-struct genl_multicast_group ieee802154_coord_mcgrp = {
-	.name		= IEEE802154_MCAST_COORD_NAME,
-};
-
-struct genl_multicast_group ieee802154_beacon_mcgrp = {
-	.name		= IEEE802154_MCAST_BEACON_NAME,
-};
-
 int ieee802154_nl_assoc_indic(struct net_device *dev,
 		struct ieee802154_addr *addr, u8 cap)
 {
@@ -72,7 +64,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
 	    nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
 		goto nla_put_failure;
 
-	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
+	return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
 
 nla_put_failure:
 	nlmsg_free(msg);
@@ -98,7 +90,7 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
 	    nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
 	    nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
 		goto nla_put_failure;
-	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
+	return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
 
 nla_put_failure:
 	nlmsg_free(msg);
@@ -133,7 +125,7 @@ int ieee802154_nl_disassoc_indic(struct net_device *dev,
 	}
 	if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
 		goto nla_put_failure;
-	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
+	return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
 
 nla_put_failure:
 	nlmsg_free(msg);
@@ -157,7 +149,7 @@ int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
 		    dev->dev_addr) ||
 	    nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
 		goto nla_put_failure;
-	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
+	return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
 
 nla_put_failure:
 	nlmsg_free(msg);
@@ -183,7 +175,7 @@ int ieee802154_nl_beacon_indic(struct net_device *dev,
 	    nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) ||
 	    nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
 		goto nla_put_failure;
-	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
+	return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
 
 nla_put_failure:
 	nlmsg_free(msg);
@@ -214,7 +206,7 @@ int ieee802154_nl_scan_confirm(struct net_device *dev,
 	    (edl &&
 	     nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl)))
 		goto nla_put_failure;
-	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
+	return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
 
 nla_put_failure:
 	nlmsg_free(msg);
@@ -238,7 +230,7 @@ int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
 		    dev->dev_addr) ||
 	    nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
 		goto nla_put_failure;
-	return ieee802154_nl_mcast(msg, ieee802154_coord_mcgrp.id);
+	return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
 
 nla_put_failure:
 	nlmsg_free(msg);
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 0e1e1fb..67b0fe8 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -69,16 +69,20 @@ static struct list_head family_ht[GENL_FAM_TAB_SIZE];
  * abuses the API and thinks it can statically use group 1.
  * That group will typically conflict with other groups that
  * any proper users use.
+ * Bit 16 is marked as used since it's used for generic netlink
+ * and the code no longer marks pre-reserved IDs as used.
  * Bit 17 is marked as already used since the VFS quota code
  * also abused this API and relied on family == group ID, we
  * cater to that by giving it a static family and group ID.
  */
-static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_VFS_DQUOT);
+static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_CTRL) |
+				      BIT(GENL_ID_VFS_DQUOT);
 static unsigned long *mc_groups = &mc_group_start;
 static unsigned long mc_groups_longs = 1;
 
 static int genl_ctrl_event(int event, struct genl_family *family,
-			   struct genl_multicast_group *grp);
+			   const struct genl_multicast_group *grp,
+			   int grp_id);
 
 static inline unsigned int genl_family_hash(unsigned int id)
 {
@@ -144,66 +148,108 @@ static u16 genl_generate_id(void)
 	return 0;
 }
 
-static struct genl_multicast_group notify_grp;
-
-/**
- * genl_register_mc_group - register a multicast group
- *
- * Registers the specified multicast group and notifies userspace
- * about the new group.
- *
- * Returns 0 on success or a negative error code.
- *
- * @family: The generic netlink family the group shall be registered for.
- * @grp: The group to register, must have a name.
- */
-int genl_register_mc_group(struct genl_family *family,
-			   struct genl_multicast_group *grp)
+static int genl_allocate_reserve_groups(int n_groups, int *first_id)
 {
-	int id;
 	unsigned long *new_groups;
-	int err = 0;
+	int start = 0;
+	int i;
+	int id;
+	bool fits;
+
+	do {
+		if (start == 0)
+			id = find_first_zero_bit(mc_groups,
+						 mc_groups_longs *
+						 BITS_PER_LONG);
+		else
+			id = find_next_zero_bit(mc_groups,
+						mc_groups_longs * BITS_PER_LONG,
+						start);
+
+		fits = true;
+		for (i = id;
+		     i < min_t(int, id + n_groups,
+			       mc_groups_longs * BITS_PER_LONG);
+		     i++) {
+			if (test_bit(i, mc_groups)) {
+				start = i;
+				fits = false;
+				break;
+			}
+		}
 
-	BUG_ON(grp->name[0] == '\0');
-	BUG_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL);
+		if (id >= mc_groups_longs * BITS_PER_LONG) {
+			unsigned long new_longs = mc_groups_longs +
+						  BITS_TO_LONGS(n_groups);
+			size_t nlen = new_longs * sizeof(unsigned long);
+
+			if (mc_groups == &mc_group_start) {
+				new_groups = kzalloc(nlen, GFP_KERNEL);
+				if (!new_groups)
+					return -ENOMEM;
+				mc_groups = new_groups;
+				*mc_groups = mc_group_start;
+			} else {
+				new_groups = krealloc(mc_groups, nlen,
+						      GFP_KERNEL);
+				if (!new_groups)
+					return -ENOMEM;
+				mc_groups = new_groups;
+				for (i = 0; i < BITS_TO_LONGS(n_groups); i++)
+					mc_groups[mc_groups_longs + i] = 0;
+			}
+			mc_groups_longs = new_longs;
+		}
+	} while (!fits);
 
-	genl_lock_all();
+	for (i = id; i < id + n_groups; i++)
+		set_bit(i, mc_groups);
+	*first_id = id;
+	return 0;
+}
+
+static struct genl_family genl_ctrl;
+
+static int genl_validate_assign_mc_groups(struct genl_family *family)
+{
+	int first_id;
+	int n_groups = family->n_mcgrps;
+	int err, i;
+
+	if (!n_groups)
+		return 0;
+
+	for (i = 0; i < n_groups; i++) {
+		const struct genl_multicast_group *grp = &family->mcgrps[i];
+
+		if (WARN_ON(grp->name[0] == '\0'))
+			return -EINVAL;
+		if (WARN_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL))
+			return -EINVAL;
+	}
 
 	/* special-case our own group and hacks */
-	if (grp == &notify_grp)
-		id = GENL_ID_CTRL;
-	else if (strcmp(family->name, "NET_DM") == 0)
-		id = 1;
-	else if (strcmp(family->name, "VFS_DQUOT") == 0)
-		id = GENL_ID_VFS_DQUOT;
-	else
-		id = find_first_zero_bit(mc_groups,
-					 mc_groups_longs * BITS_PER_LONG);
-
-
-	if (id >= mc_groups_longs * BITS_PER_LONG) {
-		size_t nlen = (mc_groups_longs + 1) * sizeof(unsigned long);
-
-		if (mc_groups == &mc_group_start) {
-			new_groups = kzalloc(nlen, GFP_KERNEL);
-			if (!new_groups) {
-				err = -ENOMEM;
-				goto out;
-			}
-			mc_groups = new_groups;
-			*mc_groups = mc_group_start;
-		} else {
-			new_groups = krealloc(mc_groups, nlen, GFP_KERNEL);
-			if (!new_groups) {
-				err = -ENOMEM;
-				goto out;
-			}
-			mc_groups = new_groups;
-			mc_groups[mc_groups_longs] = 0;
-		}
-		mc_groups_longs++;
+	if (family == &genl_ctrl) {
+		first_id = GENL_ID_CTRL;
+		BUG_ON(n_groups != 1);
+	} else if (strcmp(family->name, "NET_DM") == 0) {
+		first_id = 1;
+		BUG_ON(n_groups != 1);
+	} else if (strcmp(family->name, "VFS_DQUOT") == 0) {
+		first_id = GENL_ID_VFS_DQUOT;
+		BUG_ON(n_groups != 1);
+	} else {
+		err = genl_allocate_reserve_groups(n_groups, &first_id);
+		if (err)
+			return err;
 	}
 
+	family->mcgrp_offset = first_id;
+
+	/* if still initializing, can't and don't need to to realloc bitmaps */
+	if (!init_net.genl_sock)
+		return 0;
+
 	if (family->netnsok) {
 		struct net *net;
 
@@ -221,7 +267,7 @@ int genl_register_mc_group(struct genl_family *family,
 				 */
 				rcu_read_unlock();
 				netlink_table_ungrab();
-				goto out;
+				return err;
 			}
 		}
 		rcu_read_unlock();
@@ -230,45 +276,35 @@ int genl_register_mc_group(struct genl_family *family,
 		err = netlink_change_ngroups(init_net.genl_sock,
 					     mc_groups_longs * BITS_PER_LONG);
 		if (err)
-			goto out;
+			return err;
 	}
 
-	grp->id = id;
-	set_bit(id, mc_groups);
-	list_add_tail(&grp->list, &family->mcast_groups);
-
-	genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, family, grp);
- out:
-	genl_unlock_all();
-	return err;
+	return 0;
 }
-EXPORT_SYMBOL(genl_register_mc_group);
 
-static void __genl_unregister_mc_group(struct genl_family *family,
-				       struct genl_multicast_group *grp)
+static void genl_unregister_mc_groups(struct genl_family *family)
 {
 	struct net *net;
+	int i;
 
 	netlink_table_grab();
 	rcu_read_lock();
-	for_each_net_rcu(net)
-		__netlink_clear_multicast_users(net->genl_sock, grp->id);
+	for_each_net_rcu(net) {
+		for (i = 0; i < family->n_mcgrps; i++)
+			__netlink_clear_multicast_users(
+				net->genl_sock, family->mcgrp_offset + i);
+	}
 	rcu_read_unlock();
 	netlink_table_ungrab();
 
-	if (grp->id != 1)
-		clear_bit(grp->id, mc_groups);
-	list_del(&grp->list);
-	genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, family, grp);
-	grp->id = 0;
-}
-
-static void genl_unregister_mc_groups(struct genl_family *family)
-{
-	struct genl_multicast_group *grp, *tmp;
+	for (i = 0; i < family->n_mcgrps; i++) {
+		int grp_id = family->mcgrp_offset + i;
 
-	list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list)
-		__genl_unregister_mc_group(family, grp);
+		if (grp_id != 1)
+			clear_bit(grp_id, mc_groups);
+		genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, family,
+				&family->mcgrps[i], grp_id);
+	}
 }
 
 static int genl_validate_ops(struct genl_family *family)
@@ -314,7 +350,7 @@ static int genl_validate_ops(struct genl_family *family)
  */
 int __genl_register_family(struct genl_family *family)
 {
-	int err = -EINVAL;
+	int err = -EINVAL, i;
 
 	if (family->id && family->id < GENL_MIN_ID)
 		goto errout;
@@ -326,8 +362,6 @@ int __genl_register_family(struct genl_family *family)
 	if (err)
 		return err;
 
-	INIT_LIST_HEAD(&family->mcast_groups);
-
 	genl_lock_all();
 
 	if (genl_family_find_byname(family->name)) {
@@ -359,10 +393,18 @@ int __genl_register_family(struct genl_family *family)
 	} else
 		family->attrbuf = NULL;
 
+	err = genl_validate_assign_mc_groups(family);
+	if (err)
+		goto errout_locked;
+
 	list_add_tail(&family->family_list, genl_family_chain(family->id));
 	genl_unlock_all();
 
-	genl_ctrl_event(CTRL_CMD_NEWFAMILY, family, NULL);
+	/* send all events */
+	genl_ctrl_event(CTRL_CMD_NEWFAMILY, family, NULL, 0);
+	for (i = 0; i < family->n_mcgrps; i++)
+		genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, family,
+				&family->mcgrps[i], family->mcgrp_offset + i);
 
 	return 0;
 
@@ -398,7 +440,7 @@ int genl_unregister_family(struct genl_family *family)
 		genl_unlock_all();
 
 		kfree(family->attrbuf);
-		genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL);
+		genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0);
 		return 0;
 	}
 
@@ -658,23 +700,26 @@ static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq,
 		nla_nest_end(skb, nla_ops);
 	}
 
-	if (!list_empty(&family->mcast_groups)) {
-		struct genl_multicast_group *grp;
+	if (family->n_mcgrps) {
 		struct nlattr *nla_grps;
-		int idx = 1;
+		int i;
 
 		nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
 		if (nla_grps == NULL)
 			goto nla_put_failure;
 
-		list_for_each_entry(grp, &family->mcast_groups, list) {
+		for (i = 0; i < family->n_mcgrps; i++) {
 			struct nlattr *nest;
+			const struct genl_multicast_group *grp;
 
-			nest = nla_nest_start(skb, idx++);
+			grp = &family->mcgrps[i];
+
+			nest = nla_nest_start(skb, i + 1);
 			if (nest == NULL)
 				goto nla_put_failure;
 
-			if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id) ||
+			if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID,
+					family->mcgrp_offset + i) ||
 			    nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME,
 					   grp->name))
 				goto nla_put_failure;
@@ -692,9 +737,9 @@ nla_put_failure:
 }
 
 static int ctrl_fill_mcgrp_info(struct genl_family *family,
-				struct genl_multicast_group *grp, u32 portid,
-				u32 seq, u32 flags, struct sk_buff *skb,
-				u8 cmd)
+				const struct genl_multicast_group *grp,
+				int grp_id, u32 portid, u32 seq, u32 flags,
+				struct sk_buff *skb, u8 cmd)
 {
 	void *hdr;
 	struct nlattr *nla_grps;
@@ -716,7 +761,7 @@ static int ctrl_fill_mcgrp_info(struct genl_family *family,
 	if (nest == NULL)
 		goto nla_put_failure;
 
-	if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id) ||
+	if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp_id) ||
 	    nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME,
 			   grp->name))
 		goto nla_put_failure;
@@ -782,9 +827,10 @@ static struct sk_buff *ctrl_build_family_msg(struct genl_family *family,
 	return skb;
 }
 
-static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_family *family,
-					    struct genl_multicast_group *grp,
-					    u32 portid, int seq, u8 cmd)
+static struct sk_buff *
+ctrl_build_mcgrp_msg(struct genl_family *family,
+		     const struct genl_multicast_group *grp,
+		     int grp_id, u32 portid, int seq, u8 cmd)
 {
 	struct sk_buff *skb;
 	int err;
@@ -793,7 +839,8 @@ static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_family *family,
 	if (skb == NULL)
 		return ERR_PTR(-ENOBUFS);
 
-	err = ctrl_fill_mcgrp_info(family, grp, portid, seq, 0, skb, cmd);
+	err = ctrl_fill_mcgrp_info(family, grp, grp_id, portid,
+				   seq, 0, skb, cmd);
 	if (err < 0) {
 		nlmsg_free(skb);
 		return ERR_PTR(err);
@@ -856,7 +903,8 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
 }
 
 static int genl_ctrl_event(int event, struct genl_family *family,
-			   struct genl_multicast_group *grp)
+			   const struct genl_multicast_group *grp,
+			   int grp_id)
 {
 	struct sk_buff *msg;
 
@@ -873,7 +921,7 @@ static int genl_ctrl_event(int event, struct genl_family *family,
 	case CTRL_CMD_NEWMCAST_GRP:
 	case CTRL_CMD_DELMCAST_GRP:
 		BUG_ON(!grp);
-		msg = ctrl_build_mcgrp_msg(family, grp, 0, 0, event);
+		msg = ctrl_build_mcgrp_msg(family, grp, grp_id, 0, 0, event);
 		break;
 	default:
 		return -EINVAL;
@@ -884,11 +932,11 @@ static int genl_ctrl_event(int event, struct genl_family *family,
 
 	if (!family->netnsok) {
 		genlmsg_multicast_netns(&genl_ctrl, &init_net, msg, 0,
-					GENL_ID_CTRL, GFP_KERNEL);
+					0, GFP_KERNEL);
 	} else {
 		rcu_read_lock();
 		genlmsg_multicast_allns(&genl_ctrl, msg, 0,
-					GENL_ID_CTRL, GFP_ATOMIC);
+					0, GFP_ATOMIC);
 		rcu_read_unlock();
 	}
 
@@ -904,8 +952,8 @@ static struct genl_ops genl_ctrl_ops[] = {
 	},
 };
 
-static struct genl_multicast_group notify_grp = {
-	.name		= "notify",
+static struct genl_multicast_group genl_ctrl_groups[] = {
+	{ .name = "notify", },
 };
 
 static int __net_init genl_pernet_init(struct net *net)
@@ -945,7 +993,8 @@ static int __init genl_init(void)
 	for (i = 0; i < GENL_FAM_TAB_SIZE; i++)
 		INIT_LIST_HEAD(&family_ht[i]);
 
-	err = genl_register_family_with_ops(&genl_ctrl, genl_ctrl_ops);
+	err = genl_register_family_with_ops_groups(&genl_ctrl, genl_ctrl_ops,
+						   genl_ctrl_groups);
 	if (err < 0)
 		goto problem;
 
@@ -953,10 +1002,6 @@ static int __init genl_init(void)
 	if (err)
 		goto problem;
 
-	err = genl_register_mc_group(&genl_ctrl, &notify_grp);
-	if (err < 0)
-		goto problem;
-
 	return 0;
 
 problem:
@@ -997,6 +1042,9 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group,
 int genlmsg_multicast_allns(struct genl_family *family, struct sk_buff *skb,
 			    u32 portid, unsigned int group, gfp_t flags)
 {
+	if (group >= family->n_mcgrps)
+		return -EINVAL;
+	group = family->mcgrp_offset + group;
 	return genlmsg_mcast(skb, portid, group, flags);
 }
 EXPORT_SYMBOL(genlmsg_multicast_allns);
@@ -1011,6 +1059,9 @@ void genl_notify(struct genl_family *family,
 	if (nlh)
 		report = nlmsg_report(nlh);
 
+	if (group >= family->n_mcgrps)
+		return;
+	group = family->mcgrp_offset + group;
 	nlmsg_notify(sk, skb, portid, group, report, flags);
 }
 EXPORT_SYMBOL(genl_notify);
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index 3092df31..a9b2342 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -30,8 +30,8 @@
 #include "nfc.h"
 #include "llcp.h"
 
-static struct genl_multicast_group nfc_genl_event_mcgrp = {
-	.name = NFC_GENL_MCAST_EVENT_NAME,
+static const struct genl_multicast_group nfc_genl_mcgrps[] = {
+	{ .name = NFC_GENL_MCAST_EVENT_NAME, },
 };
 
 static struct genl_family nfc_genl_family = {
@@ -194,8 +194,7 @@ int nfc_genl_targets_found(struct nfc_dev *dev)
 
 	genlmsg_end(msg, hdr);
 
-	return genlmsg_multicast(&nfc_genl_family, msg, 0,
-				 nfc_genl_event_mcgrp.id, GFP_ATOMIC);
+	return genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
 
 nla_put_failure:
 	genlmsg_cancel(msg, hdr);
@@ -224,8 +223,7 @@ int nfc_genl_target_lost(struct nfc_dev *dev, u32 target_idx)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(&nfc_genl_family, msg, 0,
-			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
 
 	return 0;
 
@@ -257,8 +255,7 @@ int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(&nfc_genl_family, msg, 0,
-			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
 
 	return 0;
 
@@ -288,8 +285,7 @@ int nfc_genl_tm_deactivated(struct nfc_dev *dev)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(&nfc_genl_family, msg, 0,
-			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
 
 	return 0;
 
@@ -322,8 +318,7 @@ int nfc_genl_device_added(struct nfc_dev *dev)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(&nfc_genl_family, msg, 0,
-			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
 
 	return 0;
 
@@ -353,8 +348,7 @@ int nfc_genl_device_removed(struct nfc_dev *dev)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(&nfc_genl_family, msg, 0,
-			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
 
 	return 0;
 
@@ -420,8 +414,7 @@ int nfc_genl_llc_send_sdres(struct nfc_dev *dev, struct hlist_head *sdres_list)
 
 	genlmsg_end(msg, hdr);
 
-	return genlmsg_multicast(&nfc_genl_family, msg, 0,
-				 nfc_genl_event_mcgrp.id, GFP_ATOMIC);
+	return genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
 
 nla_put_failure:
 	genlmsg_cancel(msg, hdr);
@@ -455,8 +448,7 @@ int nfc_genl_se_added(struct nfc_dev *dev, u32 se_idx, u16 type)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(&nfc_genl_family, msg, 0,
-			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
 
 	return 0;
 
@@ -487,8 +479,7 @@ int nfc_genl_se_removed(struct nfc_dev *dev, u32 se_idx)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(&nfc_genl_family, msg, 0,
-			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
 
 	return 0;
 
@@ -609,8 +600,7 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
 
 	dev->dep_link_up = true;
 
-	genlmsg_multicast(&nfc_genl_family, msg, 0,
-			  nfc_genl_event_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
 
 	return 0;
 
@@ -642,8 +632,7 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(&nfc_genl_family, msg, 0,
-			  nfc_genl_event_mcgrp.id, GFP_ATOMIC);
+	genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_ATOMIC);
 
 	return 0;
 
@@ -1148,8 +1137,7 @@ int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name,
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(&nfc_genl_family, msg, 0,
-			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
 
 	return 0;
 
@@ -1320,8 +1308,7 @@ static void se_io_cb(void *context, u8 *apdu, size_t apdu_len, int err)
 
 	genlmsg_end(msg, hdr);
 
-	genlmsg_multicast(&nfc_genl_family, msg, 0,
-			  nfc_genl_event_mcgrp.id, GFP_KERNEL);
+	genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
 
 	kfree(ctx);
 
@@ -1549,15 +1536,15 @@ int __init nfc_genl_init(void)
 {
 	int rc;
 
-	rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops);
+	rc = genl_register_family_with_ops_groups(&nfc_genl_family,
+						  nfc_genl_ops,
+						  nfc_genl_mcgrps);
 	if (rc)
 		return rc;
 
-	rc = genl_register_mc_group(&nfc_genl_family, &nfc_genl_event_mcgrp);
-
 	netlink_register_notifier(&nl_notifier);
 
-	return rc;
+	return 0;
 }
 
 /**
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 1de9446..20215ff 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -62,11 +62,10 @@
 int ovs_net_id __read_mostly;
 
 static void ovs_notify(struct genl_family *family,
-		       struct sk_buff *skb, struct genl_info *info,
-		       struct genl_multicast_group *grp)
+		       struct sk_buff *skb, struct genl_info *info)
 {
 	genl_notify(family, skb, genl_info_net(info), info->snd_portid,
-		    grp->id, info->nlhdr, GFP_KERNEL);
+		    0, info->nlhdr, GFP_KERNEL);
 }
 
 /**
@@ -878,11 +877,10 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 	ovs_unlock();
 
 	if (!IS_ERR(reply))
-		ovs_notify(&dp_flow_genl_family, reply, info,
-			   &ovs_dp_flow_multicast_group);
+		ovs_notify(&dp_flow_genl_family, reply, info);
 	else
 		netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
-				ovs_dp_flow_multicast_group.id, PTR_ERR(reply));
+				dp_flow_genl_family.mcgrp_offset, PTR_ERR(reply));
 	return 0;
 
 err_flow_free:
@@ -992,8 +990,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	ovs_flow_free(flow, true);
 	ovs_unlock();
 
-	ovs_notify(&dp_flow_genl_family, reply, info,
-		   &ovs_dp_flow_multicast_group);
+	ovs_notify(&dp_flow_genl_family, reply, info);
 	return 0;
 unlock:
 	ovs_unlock();
@@ -1240,8 +1237,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
 
 	ovs_unlock();
 
-	ovs_notify(&dp_datapath_genl_family, reply, info,
-		   &ovs_dp_datapath_multicast_group);
+	ovs_notify(&dp_datapath_genl_family, reply, info);
 	return 0;
 
 err_destroy_local_port:
@@ -1306,8 +1302,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	__dp_destroy(dp);
 	ovs_unlock();
 
-	ovs_notify(&dp_datapath_genl_family, reply, info,
-		   &ovs_dp_datapath_multicast_group);
+	ovs_notify(&dp_datapath_genl_family, reply, info);
 
 	return 0;
 unlock:
@@ -1332,14 +1327,13 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
 	if (IS_ERR(reply)) {
 		err = PTR_ERR(reply);
 		netlink_set_err(sock_net(skb->sk)->genl_sock, 0,
-				ovs_dp_datapath_multicast_group.id, err);
+				dp_datapath_genl_family.mcgrp_offset, err);
 		err = 0;
 		goto unlock;
 	}
 
 	ovs_unlock();
-	ovs_notify(&dp_datapath_genl_family, reply, info,
-		   &ovs_dp_datapath_multicast_group);
+	ovs_notify(&dp_datapath_genl_family, reply, info);
 
 	return 0;
 unlock:
@@ -1601,8 +1595,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
 		goto exit_unlock;
 	}
 
-	ovs_notify(&dp_vport_genl_family, reply, info,
-		   &ovs_dp_vport_multicast_group);
+	ovs_notify(&dp_vport_genl_family, reply, info);
 
 exit_unlock:
 	ovs_unlock();
@@ -1649,8 +1642,7 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
 	BUG_ON(err < 0);
 
 	ovs_unlock();
-	ovs_notify(&dp_vport_genl_family, reply, info,
-		   &ovs_dp_vport_multicast_group);
+	ovs_notify(&dp_vport_genl_family, reply, info);
 	return 0;
 
 exit_free:
@@ -1687,8 +1679,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	err = 0;
 	ovs_dp_detach_port(vport);
 
-	ovs_notify(&dp_vport_genl_family, reply, info,
-		   &ovs_dp_vport_multicast_group);
+	ovs_notify(&dp_vport_genl_family, reply, info);
 
 exit_unlock:
 	ovs_unlock();
@@ -1790,7 +1781,7 @@ struct genl_family_and_ops {
 	struct genl_family *family;
 	const struct genl_ops *ops;
 	int n_ops;
-	struct genl_multicast_group *group;
+	const struct genl_multicast_group *group;
 };
 
 static const struct genl_family_and_ops dp_genl_families[] = {
@@ -1828,16 +1819,12 @@ static int dp_register_genl(void)
 
 		f->family->ops = f->ops;
 		f->family->n_ops = f->n_ops;
+		f->family->mcgrps = f->group;
+		f->family->n_mcgrps = f->group ? 1 : 0;
 		err = genl_register_family(f->family);
 		if (err)
 			goto error;
 		n_registered++;
-
-		if (f->group) {
-			err = genl_register_mc_group(f->family, f->group);
-			if (err)
-				goto error;
-		}
 	}
 
 	return 0;
diff --git a/net/openvswitch/dp_notify.c b/net/openvswitch/dp_notify.c
index aa29d85..d9e50dc 100644
--- a/net/openvswitch/dp_notify.c
+++ b/net/openvswitch/dp_notify.c
@@ -35,15 +35,14 @@ static void dp_detach_port_notify(struct vport *vport)
 	ovs_dp_detach_port(vport);
 	if (IS_ERR(notify)) {
 		netlink_set_err(ovs_dp_get_net(dp)->genl_sock, 0,
-				ovs_dp_vport_multicast_group.id,
+				dp_vport_genl_family.mcgrp_offset,
 				PTR_ERR(notify));
 		return;
 	}
 
 	genlmsg_multicast_netns(&dp_vport_genl_family,
 				ovs_dp_get_net(dp), notify, 0,
-				ovs_dp_vport_multicast_group.id,
-				GFP_KERNEL);
+				0, GFP_KERNEL);
 }
 
 void ovs_dp_notify_wq(struct work_struct *work)
diff --git a/net/wimax/op-msg.c b/net/wimax/op-msg.c
index f37dd3c..c278b33 100644
--- a/net/wimax/op-msg.c
+++ b/net/wimax/op-msg.c
@@ -279,8 +279,7 @@ int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
 
 	d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size);
 	d_dump(2, dev, msg, size);
-	genlmsg_multicast(&wimax_gnl_family, skb, 0,
-			  wimax_gnl_mcg.id, GFP_KERNEL);
+	genlmsg_multicast(&wimax_gnl_family, skb, 0, 0, GFP_KERNEL);
 	d_printf(1, dev, "CTX: genl multicast done\n");
 	return 0;
 }
diff --git a/net/wimax/stack.c b/net/wimax/stack.c
index 1888874..aa9b067 100644
--- a/net/wimax/stack.c
+++ b/net/wimax/stack.c
@@ -116,8 +116,8 @@ struct sk_buff *wimax_gnl_re_state_change_alloc(
 		dev_err(dev, "RE_STCH: can't create message\n");
 		goto error_new;
 	}
-	data = genlmsg_put(report_skb, 0, wimax_gnl_mcg.id, &wimax_gnl_family,
-			   0, WIMAX_GNL_RE_STATE_CHANGE);
+	data = genlmsg_put(report_skb, 0, wimax_gnl_family.mcgrp_offset,
+			   &wimax_gnl_family, 0, WIMAX_GNL_RE_STATE_CHANGE);
 	if (data == NULL) {
 		dev_err(dev, "RE_STCH: can't put data into message\n");
 		goto error_put;
@@ -177,8 +177,7 @@ int wimax_gnl_re_state_change_send(
 		goto out;
 	}
 	genlmsg_end(report_skb, header);
-	genlmsg_multicast(&wimax_gnl_family, report_skb, 0,
-			  wimax_gnl_mcg.id, GFP_KERNEL);
+	genlmsg_multicast(&wimax_gnl_family, report_skb, 0, 0, GFP_KERNEL);
 out:
 	d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n",
 		wimax_dev, report_skb, result);
@@ -580,8 +579,8 @@ struct genl_family wimax_gnl_family = {
 	.maxattr = WIMAX_GNL_ATTR_MAX,
 };
 
-struct genl_multicast_group wimax_gnl_mcg = {
-	.name = "msg",
+static const struct genl_multicast_group wimax_gnl_mcgrps[] = {
+	{ .name = "msg", },
 };
 
 
@@ -598,21 +597,18 @@ int __init wimax_subsys_init(void)
 
 	snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name),
 		 "WiMAX");
-	result = genl_register_family_with_ops(&wimax_gnl_family,
-					       wimax_gnl_ops);
+	result = genl_register_family_with_ops_groups(&wimax_gnl_family,
+						      wimax_gnl_ops,
+						      wimax_gnl_mcgrps);
 	if (unlikely(result < 0)) {
 		printk(KERN_ERR "cannot register generic netlink family: %d\n",
 		       result);
 		goto error_register_family;
 	}
 
-	result = genl_register_mc_group(&wimax_gnl_family, &wimax_gnl_mcg);
-	if (result < 0)
-		goto error_mc_group;
 	d_fnend(4, NULL, "() = 0\n");
 	return 0;
 
-error_mc_group:
 	genl_unregister_family(&wimax_gnl_family);
 error_register_family:
 	d_fnend(4, NULL, "() = %d\n", result);
diff --git a/net/wimax/wimax-internal.h b/net/wimax/wimax-internal.h
index 8567d30..b445b82 100644
--- a/net/wimax/wimax-internal.h
+++ b/net/wimax/wimax-internal.h
@@ -86,7 +86,6 @@ void wimax_rfkill_rm(struct wimax_dev *);
 
 /* generic netlink */
 extern struct genl_family wimax_gnl_family;
-extern struct genl_multicast_group wimax_gnl_mcg;
 
 /* ops */
 int wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f20edfd..a1eb210 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -47,6 +47,25 @@ static struct genl_family nl80211_fam = {
 	.post_doit = nl80211_post_doit,
 };
 
+/* multicast groups */
+enum nl80211_multicast_groups {
+	NL80211_MCGRP_CONFIG,
+	NL80211_MCGRP_SCAN,
+	NL80211_MCGRP_REGULATORY,
+	NL80211_MCGRP_MLME,
+	NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
+};
+
+static const struct genl_multicast_group nl80211_mcgrps[] = {
+	[NL80211_MCGRP_CONFIG] = { .name = "config", },
+	[NL80211_MCGRP_SCAN] = { .name = "scan", },
+	[NL80211_MCGRP_REGULATORY] = { .name = "regulatory", },
+	[NL80211_MCGRP_MLME] = { .name = "mlme", },
+#ifdef CONFIG_NL80211_TESTMODE
+	[NL80211_MCGRP_TESTMODE] = { .name = "testmode", }
+#endif
+};
+
 /* returns ERR_PTR values */
 static struct wireless_dev *
 __cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs)
@@ -6656,10 +6675,6 @@ static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
 
 
 #ifdef CONFIG_NL80211_TESTMODE
-static struct genl_multicast_group nl80211_testmode_mcgrp = {
-	.name = "testmode",
-};
-
 static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -6869,7 +6884,7 @@ void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
 	nla_nest_end(skb, data);
 	genlmsg_end(skb, hdr);
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
-				nl80211_testmode_mcgrp.id, gfp);
+				NL80211_MCGRP_TESTMODE, gfp);
 }
 EXPORT_SYMBOL(cfg80211_testmode_event);
 #endif
@@ -9566,21 +9581,6 @@ static const struct genl_ops nl80211_ops[] = {
 	},
 };
 
-static struct genl_multicast_group nl80211_mlme_mcgrp = {
-	.name = "mlme",
-};
-
-/* multicast groups */
-static struct genl_multicast_group nl80211_config_mcgrp = {
-	.name = "config",
-};
-static struct genl_multicast_group nl80211_scan_mcgrp = {
-	.name = "scan",
-};
-static struct genl_multicast_group nl80211_regulatory_mcgrp = {
-	.name = "regulatory",
-};
-
 /* notification functions */
 
 void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
@@ -9598,7 +9598,7 @@ void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev)
 	}
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_config_mcgrp.id, GFP_KERNEL);
+				NL80211_MCGRP_CONFIG, GFP_KERNEL);
 }
 
 static int nl80211_add_scan_req(struct sk_buff *msg,
@@ -9708,7 +9708,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
 	}
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_scan_mcgrp.id, GFP_KERNEL);
+				NL80211_MCGRP_SCAN, GFP_KERNEL);
 }
 
 void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
@@ -9727,7 +9727,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
 	}
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_scan_mcgrp.id, GFP_KERNEL);
+				NL80211_MCGRP_SCAN, GFP_KERNEL);
 }
 
 void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
@@ -9746,7 +9746,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
 	}
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_scan_mcgrp.id, GFP_KERNEL);
+				NL80211_MCGRP_SCAN, GFP_KERNEL);
 }
 
 void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
@@ -9765,7 +9765,7 @@ void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
 	}
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_scan_mcgrp.id, GFP_KERNEL);
+				NL80211_MCGRP_SCAN, GFP_KERNEL);
 }
 
 void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
@@ -9783,7 +9783,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
 	}
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_scan_mcgrp.id, GFP_KERNEL);
+				NL80211_MCGRP_SCAN, GFP_KERNEL);
 }
 
 /*
@@ -9838,7 +9838,7 @@ void nl80211_send_reg_change_event(struct regulatory_request *request)
 
 	rcu_read_lock();
 	genlmsg_multicast_allns(&nl80211_fam, msg, 0,
-				nl80211_regulatory_mcgrp.id, GFP_ATOMIC);
+				NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
 	rcu_read_unlock();
 
 	return;
@@ -9874,7 +9874,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -9962,7 +9962,7 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10018,7 +10018,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10057,7 +10057,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10095,7 +10095,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, GFP_KERNEL);
+				NL80211_MCGRP_MLME, GFP_KERNEL);
 	return;
 
  nla_put_failure:
@@ -10129,7 +10129,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10170,7 +10170,7 @@ void cfg80211_notify_new_peer_candidate(struct net_device *dev, const u8 *addr,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10209,7 +10209,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10262,7 +10262,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
 
 	rcu_read_lock();
 	genlmsg_multicast_allns(&nl80211_fam, msg, 0,
-				nl80211_regulatory_mcgrp.id, GFP_ATOMIC);
+				NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
 	rcu_read_unlock();
 
 	return;
@@ -10308,7 +10308,7 @@ static void nl80211_send_remain_on_chan_event(
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10363,7 +10363,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
 	}
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 }
 EXPORT_SYMBOL(cfg80211_new_sta);
 
@@ -10393,7 +10393,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10429,7 +10429,7 @@ void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10591,7 +10591,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10640,7 +10640,7 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10685,7 +10685,7 @@ static void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10743,7 +10743,7 @@ nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10790,7 +10790,7 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10867,7 +10867,7 @@ void cfg80211_cqm_txe_notify(struct net_device *dev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10916,7 +10916,7 @@ nl80211_radar_notify(struct cfg80211_registered_device *rdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -10963,7 +10963,7 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -11003,7 +11003,7 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -11155,7 +11155,7 @@ void cfg80211_report_wowlan_wakeup(struct wireless_dev *wdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  free_msg:
@@ -11197,7 +11197,7 @@ void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, gfp);
+				NL80211_MCGRP_MLME, gfp);
 	return;
 
  nla_put_failure:
@@ -11280,7 +11280,7 @@ void cfg80211_ft_event(struct net_device *netdev,
 	genlmsg_end(msg, hdr);
 
 	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
-				nl80211_mlme_mcgrp.id, GFP_KERNEL);
+				NL80211_MCGRP_MLME, GFP_KERNEL);
 }
 EXPORT_SYMBOL(cfg80211_ft_event);
 
@@ -11329,32 +11329,11 @@ int nl80211_init(void)
 {
 	int err;
 
-	err = genl_register_family_with_ops(&nl80211_fam, nl80211_ops);
+	err = genl_register_family_with_ops_groups(&nl80211_fam, nl80211_ops,
+						   nl80211_mcgrps);
 	if (err)
 		return err;
 
-	err = genl_register_mc_group(&nl80211_fam, &nl80211_config_mcgrp);
-	if (err)
-		goto err_out;
-
-	err = genl_register_mc_group(&nl80211_fam, &nl80211_scan_mcgrp);
-	if (err)
-		goto err_out;
-
-	err = genl_register_mc_group(&nl80211_fam, &nl80211_regulatory_mcgrp);
-	if (err)
-		goto err_out;
-
-	err = genl_register_mc_group(&nl80211_fam, &nl80211_mlme_mcgrp);
-	if (err)
-		goto err_out;
-
-#ifdef CONFIG_NL80211_TESTMODE
-	err = genl_register_mc_group(&nl80211_fam, &nl80211_testmode_mcgrp);
-	if (err)
-		goto err_out;
-#endif
-
 	err = netlink_register_notifier(&nl80211_netlink_notifier);
 	if (err)
 		goto err_out;
-- 
1.8.4.rc3

^ permalink raw reply related

* Re: [PATCH 1/2] net: ipv6: af_inet6: Fix warning when CONFIG_SYSCTL=n
From: Vlad Yasevich @ 2013-11-16 18:05 UTC (permalink / raw)
  To: Fabio Estevam, davem; +Cc: netdev, Fabio Estevam
In-Reply-To: <1384570328-21666-1-git-send-email-festevam@gmail.com>

On 11/15/2013 09:52 PM, Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam@freescale.com>
> 
> When CONFIG_SYSCTL=n the following build warning happens:
> 
> net/ipv6/af_inet6.c:710:13: warning: 'ipv6_packet_cleanup' defined but not used [-Wunused-function]
> 
> ipv6_packet_cleanup() is only used when CONFIG_SYSCTL=y, so protect its 
> definition with an'ifdef CONFIG_SYSCTL'.
> 
> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
> ---
>  net/ipv6/af_inet6.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
> index ff75313..e4ad65c 100644
> --- a/net/ipv6/af_inet6.c
> +++ b/net/ipv6/af_inet6.c
> @@ -707,10 +707,12 @@ static int __init ipv6_packet_init(void)
>  	return 0;
>  }
>  
> +#ifdef CONFIG_SYSCTL
>  static void ipv6_packet_cleanup(void)
>  {
>  	dev_remove_pack(&ipv6_packet_type);
>  }
> +#endif
>  
>  static int __net_init ipv6_init_mibs(struct net *net)
>  {
> 

NACK.  ipv6_packet_init and ipv6_packet_cleanup should in no way depend
on sysctl.

-vlad

^ permalink raw reply

* Re: [PATCH 1/2] net: ipv6: af_inet6: Fix warning when CONFIG_SYSCTL=n
From: Vlad Yasevich @ 2013-11-16 18:22 UTC (permalink / raw)
  To: Fabio Estevam, davem; +Cc: netdev, Fabio Estevam
In-Reply-To: <5287B3E2.2030301@gmail.com>

On 11/16/2013 01:05 PM, Vlad Yasevich wrote:
> On 11/15/2013 09:52 PM, Fabio Estevam wrote:
>> From: Fabio Estevam <fabio.estevam@freescale.com>
>>
>> When CONFIG_SYSCTL=n the following build warning happens:
>>
>> net/ipv6/af_inet6.c:710:13: warning: 'ipv6_packet_cleanup' defined but not used [-Wunused-function]
>>
>> ipv6_packet_cleanup() is only used when CONFIG_SYSCTL=y, so protect its 
>> definition with an'ifdef CONFIG_SYSCTL'.
>>
>> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
>> ---
>>  net/ipv6/af_inet6.c | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
>> index ff75313..e4ad65c 100644
>> --- a/net/ipv6/af_inet6.c
>> +++ b/net/ipv6/af_inet6.c
>> @@ -707,10 +707,12 @@ static int __init ipv6_packet_init(void)
>>  	return 0;
>>  }
>>  
>> +#ifdef CONFIG_SYSCTL
>>  static void ipv6_packet_cleanup(void)
>>  {
>>  	dev_remove_pack(&ipv6_packet_type);
>>  }
>> +#endif
>>  
>>  static int __net_init ipv6_init_mibs(struct net *net)
>>  {
>>
> 
> NACK.  ipv6_packet_init and ipv6_packet_cleanup should in no way depend
> on sysctl.
> 
> -vlad
> 

It actually appears a bit worse then that.  Looks like the inet6_init()
error were a bit messed up after the introduction of ping socket support.

-vlad

^ permalink raw reply

* Re: [PATCH 1/2] net: ipv6: af_inet6: Fix warning when CONFIG_SYSCTL=n
From: Hannes Frederic Sowa @ 2013-11-16 18:26 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: Fabio Estevam, davem, netdev, Fabio Estevam
In-Reply-To: <5287B3E2.2030301@gmail.com>

On Sat, Nov 16, 2013 at 01:05:22PM -0500, Vlad Yasevich wrote:
> On 11/15/2013 09:52 PM, Fabio Estevam wrote:
> > From: Fabio Estevam <fabio.estevam@freescale.com>
> > 
> > When CONFIG_SYSCTL=n the following build warning happens:
> > 
> > net/ipv6/af_inet6.c:710:13: warning: 'ipv6_packet_cleanup' defined but not used [-Wunused-function]
> > 
> > ipv6_packet_cleanup() is only used when CONFIG_SYSCTL=y, so protect its 
> > definition with an'ifdef CONFIG_SYSCTL'.
> > 
> > Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
> > ---
> >  net/ipv6/af_inet6.c | 2 ++
> >  1 file changed, 2 insertions(+)
> > 
> > diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
> > index ff75313..e4ad65c 100644
> > --- a/net/ipv6/af_inet6.c
> > +++ b/net/ipv6/af_inet6.c
> > @@ -707,10 +707,12 @@ static int __init ipv6_packet_init(void)
> >  	return 0;
> >  }
> >  
> > +#ifdef CONFIG_SYSCTL
> >  static void ipv6_packet_cleanup(void)
> >  {
> >  	dev_remove_pack(&ipv6_packet_type);
> >  }
> > +#endif
> >  
> >  static int __net_init ipv6_init_mibs(struct net *net)
> >  {
> > 
> 
> NACK.  ipv6_packet_init and ipv6_packet_cleanup should in no way depend
> on sysctl.

It is only used in an error path if CONFIG_SYSCTL=y. I agree it does
look a bit odd.

Maybe just add __maybe_unused to ipv6_packet_cleanup?

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox