summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_txp.c
diff options
context:
space:
mode:
authorJason Wright <jason@cvs.openbsd.org>2001-04-10 19:52:39 +0000
committerJason Wright <jason@cvs.openbsd.org>2001-04-10 19:52:39 +0000
commit9623db3e654457466edc1cceea829c0b2d9a6720 (patch)
treeff16c546acc36969180f8ecb567d5a63b2f34c2e /sys/dev/pci/if_txp.c
parent4fb16121e234db7f533a59fb7f6bb6fa41f4892c (diff)
receive filter programming
Diffstat (limited to 'sys/dev/pci/if_txp.c')
-rw-r--r--sys/dev/pci/if_txp.c73
1 files changed, 72 insertions, 1 deletions
diff --git a/sys/dev/pci/if_txp.c b/sys/dev/pci/if_txp.c
index 6844515db2a..24b877648da 100644
--- a/sys/dev/pci/if_txp.c
+++ b/sys/dev/pci/if_txp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_txp.c,v 1.9 2001/04/09 22:04:59 jason Exp $ */
+/* $OpenBSD: if_txp.c,v 1.10 2001/04/10 19:52:37 jason Exp $ */
/*
* Copyright (c) 2001
@@ -103,6 +103,7 @@ int txp_download_fw_section __P((struct txp_softc *,
int txp_alloc_rings __P((struct txp_softc *));
void txp_dma_free __P((struct txp_softc *, struct txp_dma_alloc *));
int txp_dma_malloc __P((struct txp_softc *, bus_size_t, struct txp_dma_alloc *));
+void txp_set_filter __P((struct txp_softc *));
int txp_cmd_desc_numfree __P((struct txp_softc *));
int txp_command __P((struct txp_softc *, u_int16_t, u_int16_t, u_int32_t,
@@ -1156,3 +1157,73 @@ txp_show_descriptor(d)
}
#endif
}
+
+void
+txp_set_filter(sc)
+ struct txp_softc *sc;
+{
+ struct arpcom *ac = &sc->sc_arpcom;
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ u_int32_t crc, carry, hashbit, hash[2];
+ u_int16_t filter = 0;
+ u_int8_t octet;
+ int i, j, mcnt = 0;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+
+again:
+ if (ifp->if_flags & IFF_PROMISC)
+ filter = TXP_RXFILT_PROMISC;
+ else if (ifp->if_flags & IFF_ALLMULTI)
+ filter = TXP_RXFILT_DIRECT | TXP_RXFILT_ALLMULTI |
+ TXP_RXFILT_BROADCAST;
+ else {
+ filter = TXP_RXFILT_DIRECT | TXP_RXFILT_BROADCAST;
+ hash[0] = hash[1] = 0;
+
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
+ /*
+ * addresses. For now, just accept all
+ * multicasts, rather than trying to set only
+ * those filter bits needed to match the range.
+ * (At this time, the only use of address
+ * ranges is for IP multicast routing, for
+ * which the range is big enough to require
+ * all bits set.)
+ */
+ ifp->if_flags |= IFF_ALLMULTI;
+ goto again;
+ }
+
+ mcnt++;
+ crc = 0xffffffff;
+
+ for (i = 0; i < ETHER_ADDR_LEN; i++) {
+ octet = enm->enm_addrlo[i];
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^
+ (octet & 1);
+ crc <<= 1;
+ octet >>= 1;
+ if (carry)
+ crc = (crc ^ TXP_POLYNOMIAL) |
+ carry;
+ }
+ }
+ hashbit = (u_int16_t)(crc & (64 - 1));
+ hash[hashbit / 32] |= (1 << hashbit % 32);
+ ETHER_NEXT_MULTI(step, enm);
+ }
+
+ if (mcnt > 0) {
+ filter |= TXP_RXFILT_HASHMULTI;
+ txp_command(sc, TXP_CMD_MCAST_HASH_MASK_WRITE,
+ 2, hash[0], hash[1], NULL, NULL, NULL, 0);
+ }
+ }
+
+ txp_command(sc, TXP_CMD_RX_FILTER_WRITE, filter, 0, 0,
+ NULL, NULL, NULL, 0);
+}