From patchwork Fri Oct 15 03:41:53 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Hutchings X-Patchwork-Id: 67882 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 948B6B70DE for ; Fri, 15 Oct 2010 14:42:37 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756094Ab0JODmd (ORCPT ); Thu, 14 Oct 2010 23:42:33 -0400 Received: from shadbolt.e.decadent.org.uk ([88.96.1.126]:44818 "EHLO shadbolt.e.decadent.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755719Ab0JODmc convert rfc822-to-8bit (ORCPT ); Thu, 14 Oct 2010 23:42:32 -0400 Received: from [192.168.4.185] (helo=localhost) by shadbolt.decadent.org.uk with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1P6bB5-0005OT-DU; Fri, 15 Oct 2010 04:42:28 +0100 Received: from ben by localhost with local (Exim 4.72) (envelope-from ) id 1P6bB3-0003Yr-O1; Fri, 15 Oct 2010 04:41:53 +0100 From: Ben Hutchings To: David Miller Cc: Florian Fainelli , netdev In-Reply-To: <1287112636.20865.13.camel@localhost> References: <1287112636.20865.13.camel@localhost> Date: Fri, 15 Oct 2010 04:41:53 +0100 Message-ID: <1287114113.20865.23.camel@localhost> Mime-Version: 1.0 X-Mailer: Evolution 2.30.3 X-SA-Exim-Connect-IP: 192.168.4.185 X-SA-Exim-Mail-From: ben@decadent.org.uk X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on shadbolt.decadent.org.uk X-Spam-Level: X-Spam-Status: No, score=-1.4 required=5.0 tests=ALL_TRUSTED autolearn=disabled version=3.2.5 Subject: [PATCHv2 net-2.6] r6040: Fix multicast filter some more X-SA-Exim-Version: 4.2.1 (built Wed, 25 Jun 2008 17:14:11 +0000) X-SA-Exim-Scanned: Yes (on shadbolt.decadent.org.uk) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This code has been broken forever, but in several different and creative ways. So far as I can work out, the R6040 MAC filter has 4 exact-match entries, the first of which the driver uses for its assigned unicast address, plus a 64-entry hash-based filter for multicast addresses (maybe unicast as well?). The original version of this code would write the first 4 multicast addresses as exact-match entries from offset 1 (bug #1: there is no entry 4 so this could write to some PHY registers). It would fill the remainder of the exact-match entries with the broadcast address (bug #2: this would overwrite the last used entry). If more than 4 multicast addresses were configured, it would set up the hash table, write some random crap to the MAC control register (bug #3) and finally walk off the end of the list when filling the exact-match entries (bug #4). All of this seems to be pointless, since it sets the promiscuous bit when the interface is made promiscuous or if >4 multicast addresses are enabled, and never clears it (bug #5, masking bug #2). The recent(ish) changes to the multicast list fixed bug #4, but completely removed the limit on iteration over the exact-match entries (bug #6). Bug #4 was reported as and more recently as . Florian Fainelli attempted to fix these in commit 3bcf8229a8c49769e48d3e0bd1e20d8e003f8106, but that actually dealt with bugs #1-3, bug #4 having been fixed in mainline at that point. That commit fixes the most important current bug #6. Signed-off-by: Ben Hutchings Cc: stable@kernel.org [2.6.35 only] --- Commit message was slightly mangled in the previous message. Ben. drivers/net/r6040.c | 22 ++++++++++++---------- 1 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 142c381..80666f0 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -893,16 +893,18 @@ static void r6040_multicast_list(struct net_device *dev) /* Multicast Address 1~4 case */ i = 0; netdev_for_each_mc_addr(ha, dev) { - if (i < MCAST_MAX) { - adrp = (u16 *) ha->addr; - iowrite16(adrp[0], ioaddr + MID_1L + 8 * i); - iowrite16(adrp[1], ioaddr + MID_1M + 8 * i); - iowrite16(adrp[2], ioaddr + MID_1H + 8 * i); - } else { - iowrite16(0xffff, ioaddr + MID_1L + 8 * i); - iowrite16(0xffff, ioaddr + MID_1M + 8 * i); - iowrite16(0xffff, ioaddr + MID_1H + 8 * i); - } + if (i >= MCAST_MAX) + break; + adrp = (u16 *) ha->addr; + iowrite16(adrp[0], ioaddr + MID_1L + 8 * i); + iowrite16(adrp[1], ioaddr + MID_1M + 8 * i); + iowrite16(adrp[2], ioaddr + MID_1H + 8 * i); + i++; + } + while (i < MCAST_MAX) { + iowrite16(0xffff, ioaddr + MID_1L + 8 * i); + iowrite16(0xffff, ioaddr + MID_1M + 8 * i); + iowrite16(0xffff, ioaddr + MID_1H + 8 * i); i++; } }