[netdrvr] eexpress: IPv6 fails - multicast problems

Taken from http://bugzilla.kernel.org/show_bug.cgi?id=10577

I was unable to access a computer containing an Intel EtherExpress 16 network
card using IPv6.

I traced this to failure of neighbour discovery. When I used an "ip -6 neigh
add" command, on the computer attempting access, to insert a binding between
the IPv6 address of the computer with the Intel EtherExpress 16 network card
and the card's ethernet address, I was able to access that computer using
IPv6.

Neighbour discovery requires working multicast. The driver sources file
eexpress.c contains an approximately 30 line function eexp_setup_filter used
when loading multicast addresses.

I found 3 problems in this function

1) It wrote the number of multicast addresses to the card instead of the
number of bytes in the multicast addresses.

2) When loading multiple multicast addresses it loaded the first one
provided multiple times instead of loading each one once.

3) The setting of pointer 'data' from 'dmi->dmi_addr' occured before the
test for the error situation of 'dmi' being NULL.

Correcting these problems allows the computer with the Intel EtherExpress 16
network card to found by IPv6 neighbour discovery.

p.s. There is some information on the Intel EtherExpress 16 at
http://www.intel.com/support/etherexpress/vintage/sb/cs-013500.htm
Datasheet for the Intel 82586 ethernet controller used by the card
http://www.datasheetcatalog.com/datasheets_pdf/8/2/5/8/82586.shtml

Signed-off-by: Bruce Robson <bns_robson@hotmail.com>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>

authored by Bruce Robson and committed by Jeff Garzik 46fa0617 1daad055

+6 -5
+6 -5
drivers/net/eexpress.c
··· 202 0x0000,Cmd_MCast, 203 0x0076, /* link to next command */ 204 #define CONF_NR_MULTICAST 0x44 205 - 0x0000, /* number of multicast addresses */ 206 #define CONF_MULTICAST 0x46 207 0x0000, 0x0000, 0x0000, /* some addresses */ 208 0x0000, 0x0000, 0x0000, ··· 1569 1570 static void eexp_setup_filter(struct net_device *dev) 1571 { 1572 - struct dev_mc_list *dmi = dev->mc_list; 1573 unsigned short ioaddr = dev->base_addr; 1574 int count = dev->mc_count; 1575 int i; ··· 1580 } 1581 1582 outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR); 1583 - outw(count, ioaddr+SHADOW(CONF_NR_MULTICAST)); 1584 - for (i = 0; i < count; i++) { 1585 - unsigned short *data = (unsigned short *)dmi->dmi_addr; 1586 if (!dmi) { 1587 printk(KERN_INFO "%s: too few multicast addresses\n", dev->name); 1588 break; ··· 1591 printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name); 1592 continue; 1593 } 1594 outw((CONF_MULTICAST+(6*i)) & ~31, ioaddr+SM_PTR); 1595 outw(data[0], ioaddr+SHADOW(CONF_MULTICAST+(6*i))); 1596 outw((CONF_MULTICAST+(6*i)+2) & ~31, ioaddr+SM_PTR);
··· 202 0x0000,Cmd_MCast, 203 0x0076, /* link to next command */ 204 #define CONF_NR_MULTICAST 0x44 205 + 0x0000, /* number of bytes in multicast address(es) */ 206 #define CONF_MULTICAST 0x46 207 0x0000, 0x0000, 0x0000, /* some addresses */ 208 0x0000, 0x0000, 0x0000, ··· 1569 1570 static void eexp_setup_filter(struct net_device *dev) 1571 { 1572 + struct dev_mc_list *dmi; 1573 unsigned short ioaddr = dev->base_addr; 1574 int count = dev->mc_count; 1575 int i; ··· 1580 } 1581 1582 outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR); 1583 + outw(6*count, ioaddr+SHADOW(CONF_NR_MULTICAST)); 1584 + for (i = 0, dmi = dev->mc_list; i < count; i++, dmi = dmi->next) { 1585 + unsigned short *data; 1586 if (!dmi) { 1587 printk(KERN_INFO "%s: too few multicast addresses\n", dev->name); 1588 break; ··· 1591 printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name); 1592 continue; 1593 } 1594 + data = (unsigned short *)dmi->dmi_addr; 1595 outw((CONF_MULTICAST+(6*i)) & ~31, ioaddr+SM_PTR); 1596 outw(data[0], ioaddr+SHADOW(CONF_MULTICAST+(6*i))); 1597 outw((CONF_MULTICAST+(6*i)+2) & ~31, ioaddr+SM_PTR);