summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/socppc/dev/if_tsec.c43
1 files changed, 38 insertions, 5 deletions
diff --git a/sys/arch/socppc/dev/if_tsec.c b/sys/arch/socppc/dev/if_tsec.c
index 67ec14712b9..4e4daad366f 100644
--- a/sys/arch/socppc/dev/if_tsec.c
+++ b/sys/arch/socppc/dev/if_tsec.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_tsec.c,v 1.14 2008/11/28 02:44:17 brad Exp $ */
+/* $OpenBSD: if_tsec.c,v 1.15 2009/01/28 21:08:22 kettenis Exp $ */
/*
* Copyright (c) 2008 Mark Kettenis
@@ -942,17 +942,50 @@ tsec_down(struct tsec_softc *sc)
void
tsec_iff(struct tsec_softc *sc)
{
+ struct arpcom *ac = &sc->sc_ac;
struct ifnet *ifp = &sc->sc_ac.ac_if;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+ uint32_t crc, hash[8];
uint32_t rctrl;
+ int i;
- rctrl = tsec_read(sc, TSEC_RCTRL);
+ ifp->if_flags &= ~IFF_ALLMULTI;
+ bzero(hash, sizeof(hash));
+
+ if ((ifp->if_flags & IFF_RUNNING) == 0)
+ goto domulti;
if (ifp->if_flags & IFF_PROMISC)
+ goto allmulti;
+
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN))
+ goto allmulti;
+
+ crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
+ crc >>= 24;
+ hash[crc / 32] |= 1 << (crc % 32);
+
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+ goto domulti;
+
+allmulti:
+ ifp->if_flags |= IFF_ALLMULTI;
+ bzero(hash, sizeof(hash));
+
+domulti:
+ for (i = 0; i < nitems(hash); i++)
+ tsec_write(sc, TSEC_IADDR0 + i * 4, hash[i]);
+
+ rctrl = tsec_read(sc, TSEC_RCTRL);
+ if (ifp->if_flags & IFF_ALLMULTI)
rctrl |= TSEC_RCTRL_PROM;
else
rctrl &= ~TSEC_RCTRL_PROM;
- tsec_write(sc, TSEC_RCTRL, rctrl | TSEC_RCTRL_PROM);
-
- /* XXX multicast */
+ tsec_write(sc, TSEC_RCTRL, rctrl);
}
int