Subject: IFF_ALLMULTI and ti/rtk/vr
To: None <tech-net@netbsd.org>
From: enami tsugutomo <enami@sm.sony.co.jp>
List: tech-net
Date: 10/02/2000 18:46:58
As far as reading the source, some driver like ti/rtk/vr doesn't DTRT
about IFF_ALLMULTI as NetBSD driver.  So, probably mrouted doesn't
works with those interface.

I guess at leaset following changes are necessary.  Could someone
review or test it?

enami.
Index: ic/rtl81x9.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/rtl81x9.c,v
retrieving revision 1.14
diff -u -r1.14 rtl81x9.c
--- ic/rtl81x9.c	2000/10/01 23:32:42	1.14
+++ ic/rtl81x9.c	2000/10/02 08:36:50
@@ -572,7 +572,9 @@
 
 	rxfilt = CSR_READ_4(sc, RTK_RXCFG);
 
-	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+	if (ifp->if_flags & IFF_PROMISC) {
+allmulti:
+		ifp->if_flags |= IFF_ALLMULTI;
 		rxfilt |= RTK_RXCFG_RX_MULTI;
 		CSR_WRITE_4(sc, RTK_RXCFG, rxfilt);
 		CSR_WRITE_4(sc, RTK_MAR0, 0xFFFFFFFF);
@@ -589,7 +591,7 @@
 	while (enm != NULL) {
 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
 		    ETHER_ADDR_LEN) != 0)
-			continue;
+			goto allmulti;
 
 		h = rtk_calchash(enm->enm_addrlo);
 		if (h < 32)
@@ -599,6 +601,8 @@
 		mcnt++;
 		ETHER_NEXT_MULTI(step, enm);
 	}
+
+	ifp->if_flags &= ~IFF_ALLMULTI;
 
 	if (mcnt)
 		rxfilt |= RTK_RXCFG_RX_MULTI;
Index: pci/if_vr.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pci/if_vr.c,v
retrieving revision 1.38
diff -u -r1.38 if_vr.c
--- pci/if_vr.c	2000/10/01 23:32:44	1.38
+++ pci/if_vr.c	2000/10/02 08:36:52
@@ -479,7 +479,9 @@
 
 	rxfilt = CSR_READ_1(sc, VR_RXCFG);
 
-	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+	if (ifp->if_flags & IFF_PROMISC) {
+allmulti:
+		ifp->if_flags |= IFF_ALLMULTI;
 		rxfilt |= VR_RXCFG_RX_MULTI;
 		CSR_WRITE_1(sc, VR_RXCFG, rxfilt);
 		CSR_WRITE_4(sc, VR_MAR0, 0xFFFFFFFF);
@@ -494,8 +496,9 @@
 	/* now program new ones */
 	ETHER_FIRST_MULTI(step, &sc->vr_ec, enm);
 	while (enm != NULL) {
-		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0)
-			continue;
+		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
+		    ETHER_ADDR_LEN) != 0)
+			goto allmulti;
 
 		h = vr_calchash(enm->enm_addrlo);
 
@@ -506,6 +509,8 @@
 		ETHER_NEXT_MULTI(step, enm);
 		mcnt++;
 	}
+
+	ifp->if_flags &= ~IFF_ALLMULTI;
 
 	if (mcnt)
 		rxfilt |= VR_RXCFG_RX_MULTI;
Index: pci/if_ti.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pci/if_ti.c,v
retrieving revision 1.11
diff -u -r1.11 if_ti.c
--- pci/if_ti.c	2000/10/01 23:32:43	1.11
+++ pci/if_ti.c	2000/10/02 08:36:53
@@ -1205,40 +1205,62 @@
 
 	ifp = &sc->ethercom.ec_if;
 
-	if (ifp->if_flags & IFF_ALLMULTI) {
-		TI_DO_CMD(TI_CMD_SET_ALLMULTI, TI_CMD_CODE_ALLMULTI_ENB, 0);
-		return;
-	} else {
-		TI_DO_CMD(TI_CMD_SET_ALLMULTI, TI_CMD_CODE_ALLMULTI_DIS, 0);
-	}
-
 	/* Disable interrupts. */
 	intrs = CSR_READ_4(sc, TI_MB_HOSTINTR);
 	CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1);
 
 	/* First, zot all the existing filters. */
-	while (SIMPLEQ_FIRST(&sc->ti_mc_listhead) != NULL) {
-		mc = SIMPLEQ_FIRST(&sc->ti_mc_listhead);
+	while ((mc = SIMPLEQ_FIRST(&sc->ti_mc_listhead)) != NULL) {
 		ti_del_mcast(sc, &mc->mc_addr);
 		SIMPLEQ_REMOVE_HEAD(&sc->ti_mc_listhead, mc, mc_entries);
 		free(mc, M_DEVBUF);
 	}
 
-	/* Now program new ones. */
+	/*
+	 * Remember all multicast addresses so that we can delete them
+	 * later.  Punt if there is a range of addresses or memory shortage.
+	 */
 	ETHER_FIRST_MULTI(step, &sc->ethercom, enm);
 	while (enm != NULL) {
-		mc = malloc(sizeof(struct ti_mc_entry), M_DEVBUF, M_NOWAIT);
-		bcopy(enm->enm_addrlo,
-		    (char *)&mc->mc_addr, ETHER_ADDR_LEN);
+		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
+		    ETHER_ADDR_LEN) != 0)
+			goto allmulti;
+		if ((mc = malloc(sizeof(struct ti_mc_entry), M_DEVBUF,
+		    M_NOWAIT)) == NULL)
+			goto allmulti;
+		memcpy(&mc->mc_addr, enm->enm_addrlo, ETHER_ADDR_LEN);
 		SIMPLEQ_INSERT_HEAD(&sc->ti_mc_listhead, mc, mc_entries);
-		ti_add_mcast(sc, &mc->mc_addr);
 		ETHER_NEXT_MULTI(step, enm);
 	}
 
+	/* Accept only programmed multicast addresses */
+	ifp->if_flags &= ~IFF_ALLMULTI;
+	TI_DO_CMD(TI_CMD_SET_ALLMULTI, TI_CMD_CODE_ALLMULTI_DIS, 0);
+
+	/* Now program new ones. */
+	for (mc = SIMPLEQ_FIRST(&sc->ti_mc_listhead); mc != NULL;
+	    mc = SIMPLEQ_NEXT(mc, mc_entries))
+		ti_add_mcast(sc, &mc->mc_addr);
+
 	/* Re-enable interrupts. */
 	CSR_WRITE_4(sc, TI_MB_HOSTINTR, intrs);
 
 	return;
+
+allmulti:
+	/* No need to keep individual multicast addresses */
+	while ((mc = SIMPLEQ_FIRST(&sc->ti_mc_listhead)) != NULL) {
+		SIMPLEQ_REMOVE_HEAD(&sc->ti_mc_listhead, mc,
+		    mc_entries);
+		free(mc, M_DEVBUF);
+	}
+
+	/* Accept all multicast addresses */
+	ifp->if_flags |= IFF_ALLMULTI;
+	TI_DO_CMD(TI_CMD_SET_ALLMULTI, TI_CMD_CODE_ALLMULTI_ENB, 0);
+
+	/* Re-enable interrupts. */
+	CSR_WRITE_4(sc, TI_MB_HOSTINTR, intrs);
 }
 
 /*
@@ -1784,6 +1806,8 @@
 		goto fail2;
 	}
 
+	SIMPLEQ_INIT(&sc->ti_mc_listhead);
+
 	/* Set default tuneable values. */
 	sc->ti_stat_ticks = 2 * TI_TICKS_PER_SEC;
 	sc->ti_rx_coal_ticks = TI_TICKS_PER_SEC / 5000;
@@ -2557,12 +2581,12 @@
 		break;
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
-		if (command == SIOCADDMULTI)
-			ether_addmulti(ifr, &sc->ethercom);
-		else
-			ether_delmulti(ifr, &sc->ethercom);
-		if (ifp->if_flags & IFF_RUNNING) {
-			ti_setmulti(sc);
+		error = (command == SIOCADDMULTI) ?
+		    ether_addmulti(ifr, &sc->ethercom) :
+		    ether_delmulti(ifr, &sc->ethercom);
+		if (error == ENETRESET) {
+			if (ifp->if_flags & IFF_RUNNING)
+				ti_setmulti(sc);
 			error = 0;
 		}
 		break;