Index: sys/arm/allwinner/if_awg.c =================================================================== --- sys/arm/allwinner/if_awg.c +++ sys/arm/allwinner/if_awg.c @@ -675,12 +675,25 @@ return (x >> 16) | (x << 16); } +static u_int +awg_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t crc, hashreg, hashbit, *hash = arg; + + crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN) & 0x7f; + crc = bitrev32(~crc) >> 26; + hashreg = (crc >> 5); + hashbit = (crc & 0x1f); + hash[hashreg] |= (1 << hashbit); + + return (1); +} + static void awg_setup_rxfilter(struct awg_softc *sc) { - uint32_t val, crc, hashreg, hashbit, hash[2], machi, maclo; - int mc_count, mcnt, i; - uint8_t *eaddr, *mta; + uint32_t val, hash[2], machi, maclo; + uint8_t *eaddr; if_t ifp; AWG_ASSERT_LOCKED(sc); @@ -689,37 +702,14 @@ val = 0; hash[0] = hash[1] = 0; - mc_count = if_multiaddr_count(ifp, -1); - if (if_getflags(ifp) & IFF_PROMISC) val |= DIS_ADDR_FILTER; else if (if_getflags(ifp) & IFF_ALLMULTI) { val |= RX_ALL_MULTICAST; hash[0] = hash[1] = ~0; - } else if (mc_count > 0) { + } else if (if_foreach_llmaddr(ifp, awg_hash_maddr, hash) > 0) val |= HASH_MULTICAST; - mta = malloc(sizeof(unsigned char) * ETHER_ADDR_LEN * mc_count, - M_DEVBUF, M_NOWAIT); - if (mta == NULL) { - if_printf(ifp, - "failed to allocate temporary multicast list\n"); - return; - } - - if_multiaddr_array(ifp, mta, &mcnt, mc_count); - for (i = 0; i < mcnt; i++) { - crc = ether_crc32_le(mta + (i * ETHER_ADDR_LEN), - ETHER_ADDR_LEN) & 0x7f; - crc = bitrev32(~crc) >> 26; - hashreg = (crc >> 5); - hashbit = (crc & 0x1f); - hash[hashreg] |= (1 << hashbit); - } - - free(mta, M_DEVBUF); - } - /* Write our unicast address */ eaddr = IF_LLADDR(ifp); machi = (eaddr[5] << 8) | eaddr[4]; Index: sys/arm/allwinner/if_emac.c =================================================================== --- sys/arm/allwinner/if_emac.c +++ sys/arm/allwinner/if_emac.c @@ -218,12 +218,22 @@ printf("MAC address: %s\n", ether_sprintf(hwaddr)); } +static u_int +emac_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t h, *hashes = arg; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + hashes[h >> 5] |= 1 << (h & 0x1f); + + return (1); +} + static void emac_set_rx_mode(struct emac_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t h, hashes[2]; + uint32_t hashes[2]; uint32_t rcr = 0; EMAC_ASSERT_LOCKED(sc); @@ -241,17 +251,8 @@ if (ifp->if_flags & IFF_ALLMULTI) { hashes[0] = 0xffffffff; hashes[1] = 0xffffffff; - } else { - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &sc->emac_ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - hashes[h >> 5] |= 1 << (h & 0x1f); - } - if_maddr_runlock(ifp); - } + } else + if_foreach_llmaddr(ifp, emac_hash_maddr, hashes); rcr |= EMAC_RX_MCO; rcr |= EMAC_RX_MHF; EMAC_WRITE_REG(sc, EMAC_RX_HASH0, hashes[0]); Index: sys/arm/ralink/if_fv.c =================================================================== --- sys/arm/ralink/if_fv.c +++ sys/arm/ralink/if_fv.c @@ -200,8 +200,25 @@ DRIVER_MODULE(mdio, fvmdio, mdio_driver, mdio_devclass, 0, 0); #endif -/* setup frame code refer dc code */ +static u_int +fv_set_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint16_t *sp = arg; + uint8_t *ma; + int i; + + ma = LLADDR(sdl); + i = cnt * 6; + sp[i] = sp[i+1] = (ma[1] << 8 | ma[0]); + i += 2; + sp[i] = sp[i+1] = (ma[3] << 8 | ma[2]); + i += 2; + sp[i] = sp[i+1] = (ma[5] << 8 | ma[4]); + + return (1); +} +/* setup frame code refer dc code */ static void fv_setfilt(struct fv_softc *sc) { @@ -209,9 +226,7 @@ struct fv_desc *sframe; int i; struct ifnet *ifp; - struct ifmultiaddr *ifma; uint16_t *sp; - uint8_t *ma; ifp = sc->fv_ifp; @@ -225,20 +240,7 @@ sframe->fv_addr = sc->fv_rdata.fv_sf_paddr; sframe->fv_devcs = ADCTL_Tx_SETUP | FV_DMASIZE(FV_SFRAME_LEN); - i = 0; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - ma = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); - sp[i] = sp[i+1] = (ma[1] << 8 | ma[0]); - i += 2; - sp[i] = sp[i+1] = (ma[3] << 8 | ma[2]); - i += 2; - sp[i] = sp[i+1] = (ma[5] << 8 | ma[4]); - i += 2; - } - if_maddr_runlock(ifp); + i = if_foreach_llmaddr(ifp, fv_set_maddr, sp) * 6; bcopy(IF_LLADDR(sc->fv_ifp), eaddr, ETHER_ADDR_LEN); sp[90] = sp[91] = eaddr[0]; Index: sys/arm/ti/cpsw/if_cpsw.c =================================================================== --- sys/arm/ti/cpsw/if_cpsw.c +++ sys/arm/ti/cpsw/if_cpsw.c @@ -2425,12 +2425,27 @@ printf("\n"); } +static u_int +cpswp_set_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct cpswp_softc *sc = arg; + uint32_t portmask; + + if (sc->swsc->dualemac) + portmask = 1 << (sc->unit + 1) | 1 << 0; + else + portmask = 7; + + cpsw_ale_mc_entry_set(sc->swsc, portmask, sc->vlan, LLADDR(sdl)); + + return (1); +} + static int cpswp_ale_update_addresses(struct cpswp_softc *sc, int purge) { uint8_t *mac; uint32_t ale_entry[3], ale_type, portmask; - struct ifmultiaddr *ifma; if (sc->swsc->dualemac) { ale_type = ALE_TYPE_VLAN_ADDR << 28 | sc->vlan << 16; @@ -2445,7 +2460,6 @@ * For simplicity, keep this entry at table index 0 for port 1 and * at index 2 for port 2 in the ALE. */ - if_addr_rlock(sc->ifp); mac = LLADDR((struct sockaddr_dl *)sc->ifp->if_addr->ifa_addr); ale_entry[0] = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; ale_entry[1] = ale_type | mac[0] << 8 | mac[1]; /* addr entry + mac */ @@ -2457,7 +2471,6 @@ mac[3] << 24 | mac[2] << 16 | mac[1] << 8 | mac[0]); cpsw_write_4(sc->swsc, CPSW_PORT_P_SA_LO(sc->unit + 1), mac[5] << 8 | mac[4]); - if_addr_runlock(sc->ifp); /* Keep the broadcast address at table entry 1 (or 3). */ ale_entry[0] = 0xffffffff; /* Lower 32 bits of MAC */ @@ -2472,14 +2485,7 @@ cpsw_ale_remove_all_mc_entries(sc->swsc); /* Set other multicast addrs desired. */ - if_maddr_rlock(sc->ifp); - CK_STAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - cpsw_ale_mc_entry_set(sc->swsc, portmask, sc->vlan, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - } - if_maddr_runlock(sc->ifp); + if_foreach_llmaddr(sc->ifp, cpswp_set_maddr, sc); return (0); } Index: sys/dev/ae/if_ae.c =================================================================== --- sys/dev/ae/if_ae.c +++ sys/dev/ae/if_ae.c @@ -2031,12 +2031,21 @@ AE_WRITE_4(sc, AE_MAC_REG, val); } +static u_int +ae_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t crc, *mchash = arg; + + crc = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); + mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); + + return (1); +} + static void ae_rxfilter(ae_softc_t *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t crc; uint32_t mchash[2]; uint32_t rxcfg; @@ -2072,15 +2081,7 @@ * Load multicast tables. */ bzero(mchash, sizeof(mchash)); - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, ae_hash_maddr, &mchash); AE_WRITE_4(sc, AE_REG_MHT0, mchash[0]); AE_WRITE_4(sc, AE_REG_MHT1, mchash[1]); AE_WRITE_4(sc, AE_MAC_REG, rxcfg); Index: sys/dev/age/if_age.c =================================================================== --- sys/dev/age/if_age.c +++ sys/dev/age/if_age.c @@ -3140,12 +3140,22 @@ CSR_WRITE_4(sc, AGE_MAC_CFG, reg); } +static u_int +age_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *mchash = arg; + uint32_t crc; + + crc = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); + mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); + + return (1); +} + static void age_rxfilter(struct age_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t crc; uint32_t mchash[2]; uint32_t rxcfg; @@ -3170,16 +3180,7 @@ /* Program new filter. */ bzero(mchash, sizeof(mchash)); - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &sc->age_ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, age_hash_maddr, mchash); CSR_WRITE_4(sc, AGE_MAR0, mchash[0]); CSR_WRITE_4(sc, AGE_MAR1, mchash[1]); Index: sys/dev/al_eth/al_eth.c =================================================================== --- sys/dev/al_eth/al_eth.c +++ sys/dev/al_eth/al_eth.c @@ -603,7 +603,7 @@ static void al_eth_mac_table_unicast_add(struct al_eth_adapter *adapter, - uint8_t idx, uint8_t *addr, uint8_t udma_mask) + uint8_t idx, uint8_t udma_mask) { struct al_eth_fwd_mac_table_entry entry = { { 0 } }; @@ -2876,6 +2876,30 @@ } } +static u_int +al_count_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + unsigned char *mac; + + mac = LLADDR(sdl); + /* default mc address inside mac address */ + if (mac[3] != 0 && mac[4] != 0 && mac[5] != 1) + return (1); + else + return (0); +} + +static u_int +al_program_addr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct al_eth_adapter *adapter = arg; + + al_eth_mac_table_unicast_add(adapter, + AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + 1 + cnt, 1); + + return (1); +} + /* * Unicast, Multicast and Promiscuous mode set * @@ -2884,43 +2908,16 @@ * responsible for configuring the hardware for proper unicast, multicast, * promiscuous mode, and all-multi behavior. */ -#define MAX_NUM_MULTICAST_ADDRESSES 32 -#define MAX_NUM_ADDRESSES 32 - static void al_eth_set_rx_mode(struct al_eth_adapter *adapter) { struct ifnet *ifp = adapter->netdev; - struct ifmultiaddr *ifma; /* multicast addresses configured */ - struct ifaddr *ifua; /* unicast address */ - int mc = 0; - int uc = 0; + int mc, uc; uint8_t i; - unsigned char *mac; - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (mc == MAX_NUM_MULTICAST_ADDRESSES) - break; - mac = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); - /* default mc address inside mac address */ - if (mac[3] != 0 && mac[4] != 0 && mac[5] != 1) - mc++; - } - if_maddr_runlock(ifp); - - if_addr_rlock(ifp); - CK_STAILQ_FOREACH(ifua, &ifp->if_addrhead, ifa_link) { - if (ifua->ifa_addr->sa_family != AF_LINK) - continue; - if (uc == MAX_NUM_ADDRESSES) - break; - uc++; - } - if_addr_runlock(ifp); + /* XXXGL: why generic count won't work? */ + mc = if_foreach_llmaddr(ifp, al_count_maddr, NULL); + uc = if_lladdr_count(ifp); if ((ifp->if_flags & IFF_PROMISC) != 0) { al_eth_mac_table_promiscuous_set(adapter, true); @@ -2957,18 +2954,7 @@ } /* set new addresses */ - i = AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + 1; - if_addr_rlock(ifp); - CK_STAILQ_FOREACH(ifua, &ifp->if_addrhead, ifa_link) { - if (ifua->ifa_addr->sa_family != AF_LINK) { - continue; - } - al_eth_mac_table_unicast_add(adapter, i, - (unsigned char *)ifua->ifa_addr, 1); - i++; - } - if_addr_runlock(ifp); - + if_foreach_lladdr(ifp, al_program_addr, adapter); } al_eth_mac_table_promiscuous_set(adapter, false); } @@ -3001,7 +2987,7 @@ * MAC address and all broadcast. all the rest will be dropped. */ al_eth_mac_table_unicast_add(adapter, AL_ETH_MAC_TABLE_UNICAST_IDX_BASE, - adapter->mac_addr, 1); + 1); al_eth_mac_table_broadcast_add(adapter, AL_ETH_MAC_TABLE_BROADCAST_IDX, 1); al_eth_mac_table_promiscuous_set(adapter, false); Index: sys/dev/alc/if_alc.c =================================================================== --- sys/dev/alc/if_alc.c +++ sys/dev/alc/if_alc.c @@ -4581,12 +4581,22 @@ CSR_WRITE_4(sc, ALC_MAC_CFG, reg); } +static u_int +alc_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *mchash = arg; + uint32_t crc; + + crc = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); + mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); + + return (1); +} + static void alc_rxfilter(struct alc_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t crc; uint32_t mchash[2]; uint32_t rxcfg; @@ -4609,15 +4619,7 @@ goto chipit; } - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &sc->alc_ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, alc_hash_maddr, mchash); chipit: CSR_WRITE_4(sc, ALC_MAR0, mchash[0]); Index: sys/dev/ale/if_ale.c =================================================================== --- sys/dev/ale/if_ale.c +++ sys/dev/ale/if_ale.c @@ -3008,12 +3008,21 @@ CSR_WRITE_4(sc, ALE_MAC_CFG, reg); } +static u_int +ale_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t crc, *mchash = arg; + + crc = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); + mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); + + return (1); +} + static void ale_rxfilter(struct ale_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t crc; uint32_t mchash[2]; uint32_t rxcfg; @@ -3038,16 +3047,7 @@ /* Program new filter. */ bzero(mchash, sizeof(mchash)); - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &sc->ale_ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, ale_hash_maddr, &mchash); CSR_WRITE_4(sc, ALE_MAR0, mchash[0]); CSR_WRITE_4(sc, ALE_MAR1, mchash[1]); Index: sys/dev/altera/atse/if_atse.c =================================================================== --- sys/dev/altera/atse/if_atse.c +++ sys/dev/altera/atse/if_atse.c @@ -427,12 +427,14 @@ return (0); } -static uint8_t -atse_mchash(struct atse_softc *sc __unused, const uint8_t *addr) +static u_int +atse_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) { - uint8_t x, y; + uint64_t *h = arg; + uint8_t *addr, x, y; int i, j; + addr = LLADDR(sdl); x = 0; for (i = 0; i < ETHER_ADDR_LEN; i++) { y = addr[i] & 0x01; @@ -440,14 +442,14 @@ y ^= (addr[i] >> j) & 0x01; x |= (y << i); } + *h |= (1 << x); - return (x); + return (1); } static int atse_rxfilter_locked(struct atse_softc *sc) { - struct ifmultiaddr *ifma; struct ifnet *ifp; uint32_t val4; int i; @@ -478,22 +480,13 @@ */ uint64_t h; - h = 0; /* * Re-build and re-program hash table. First build the * bit-field "yes" or "no" for each slot per address, then * do all the programming afterwards. */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) { - continue; - } - - h |= (1 << atse_mchash(sc, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr))); - } - if_maddr_runlock(ifp); + h = 0; + (void)if_foreach_llmaddr(ifp, atse_hash_maddr, &h); for (i = 0; i <= MHASH_LEN; i++) { CSR_WRITE_4(sc, MHASH_START + i, (h & (1 << i)) ? 0x01 : 0x00); Index: sys/dev/ath/if_ath.c =================================================================== --- sys/dev/ath/if_ath.c +++ sys/dev/ath/if_ath.c @@ -3591,6 +3591,25 @@ DPRINTF(sc, ATH_DEBUG_MODE, "%s: RX filter 0x%x\n", __func__, rfilt); } +static u_int +ath_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t val, *mfilt = arg; + char *dl; + uint8_t pos; + + /* calculate XOR of eight 6bit values */ + dl = LLADDR(sdl); + val = le32dec(dl + 0); + pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + val = le32dec(dl + 3); + pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + pos &= 0x3f; + mfilt[pos / 32] |= (1 << (pos % 32)); + + return (1); +} + /* * Driver-internal mcast update call. * @@ -3605,35 +3624,13 @@ /* calculate and install multicast filter */ if (ic->ic_allmulti == 0) { struct ieee80211vap *vap; - struct ifnet *ifp; - struct ifmultiaddr *ifma; /* * Merge multicast addresses to form the hardware filter. */ mfilt[0] = mfilt[1] = 0; - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - ifp = vap->iv_ifp; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - caddr_t dl; - uint32_t val; - uint8_t pos; - - /* calculate XOR of eight 6bit values */ - dl = LLADDR((struct sockaddr_dl *) - ifma->ifma_addr); - val = le32dec(dl + 0); - pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ - val; - val = le32dec(dl + 3); - pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ - val; - pos &= 0x3f; - mfilt[pos / 32] |= (1 << (pos % 32)); - } - if_maddr_runlock(ifp); - } + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if_foreach_llmaddr(vap->iv_ifp, ath_hash_maddr, &mfilt); } else mfilt[0] = mfilt[1] = ~0; Index: sys/dev/bce/if_bce.c =================================================================== --- sys/dev/bce/if_bce.c +++ sys/dev/bce/if_bce.c @@ -8065,14 +8065,25 @@ /* Returns: */ /* Nothing. */ /****************************************************************************/ +static u_int +bce_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + u32 *hashes = arg; + int h; + + h = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN) & 0xFF; + hashes[(h & 0xE0) >> 5] |= 1 << (h & 0x1F); + + return (1); +} + static void bce_set_rx_mode(struct bce_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; u32 hashes[NUM_MC_HASH_REGISTERS] = { 0, 0, 0, 0, 0, 0, 0, 0 }; u32 rx_mode, sort_mode; - int h, i; + int i; DBENTER(BCE_VERBOSE_MISC); @@ -8115,16 +8126,7 @@ } else { /* Accept one or more multicast(s). */ DBPRINT(sc, BCE_INFO_MISC, "Enabling selective multicast mode.\n"); - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_le(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) & 0xFF; - hashes[(h & 0xE0) >> 5] |= 1 << (h & 0x1F); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, bce_hash_maddr, hashes); for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) REG_WR(sc, BCE_EMAC_MULTICAST_HASH0 + (i * 4), hashes[i]); Index: sys/dev/bfe/if_bfe.c =================================================================== --- sys/dev/bfe/if_bfe.c +++ sys/dev/bfe/if_bfe.c @@ -1080,13 +1080,21 @@ bfe_wait_bit(sc, BFE_CAM_CTRL, BFE_CAM_BUSY, 10000, 1); } +static u_int +bfe_write_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct bfe_softc *sc = arg; + + bfe_cam_write(sc, LLADDR(sdl), cnt + 1); + + return (1); +} + static void bfe_set_rx_mode(struct bfe_softc *sc) { struct ifnet *ifp = sc->bfe_ifp; - struct ifmultiaddr *ifma; u_int32_t val; - int i = 0; BFE_LOCK_ASSERT(sc); @@ -1104,20 +1112,13 @@ CSR_WRITE_4(sc, BFE_CAM_CTRL, 0); - bfe_cam_write(sc, IF_LLADDR(sc->bfe_ifp), i++); + bfe_cam_write(sc, IF_LLADDR(sc->bfe_ifp), 0); if (ifp->if_flags & IFF_ALLMULTI) val |= BFE_RXCONF_ALLMULTI; else { val &= ~BFE_RXCONF_ALLMULTI; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - bfe_cam_write(sc, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr), i++); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, bfe_write_maddr, sc); } CSR_WRITE_4(sc, BFE_RXCONF, val); Index: sys/dev/bge/if_bge.c =================================================================== --- sys/dev/bge/if_bge.c +++ sys/dev/bge/if_bge.c @@ -1621,33 +1621,32 @@ BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_PROMISC); } +static u_int +bge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *hashes = arg; + int h; + + h = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN) & 0x7F; + hashes[(h & 0x60) >> 5] |= 1 << (h & 0x1F); + + return (1); +} + static void bge_setmulti(struct bge_softc *sc) { if_t ifp; - int mc_count = 0; uint32_t hashes[4] = { 0, 0, 0, 0 }; - int h, i, mcnt; - unsigned char *mta; + int i; BGE_LOCK_ASSERT(sc); ifp = sc->bge_ifp; - mc_count = if_multiaddr_count(ifp, -1); - mta = malloc(sizeof(unsigned char) * ETHER_ADDR_LEN * - mc_count, M_DEVBUF, M_NOWAIT); - - if(mta == NULL) { - device_printf(sc->bge_dev, - "Failed to allocated temp mcast list\n"); - return; - } - if (if_getflags(ifp) & IFF_ALLMULTI || if_getflags(ifp) & IFF_PROMISC) { for (i = 0; i < 4; i++) CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0xFFFFFFFF); - free(mta, M_DEVBUF); return; } @@ -1655,17 +1654,10 @@ for (i = 0; i < 4; i++) CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0); - if_multiaddr_array(ifp, mta, &mcnt, mc_count); - for(i = 0; i < mcnt; i++) { - h = ether_crc32_le(mta + (i * ETHER_ADDR_LEN), - ETHER_ADDR_LEN) & 0x7F; - hashes[(h & 0x60) >> 5] |= 1 << (h & 0x1F); - } + if_foreach_llmaddr(ifp, bge_hash_maddr, hashes); for (i = 0; i < 4; i++) CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), hashes[i]); - - free(mta, M_DEVBUF); } static void Index: sys/dev/bnxt/if_bnxt.c =================================================================== --- sys/dev/bnxt/if_bnxt.c +++ sys/dev/bnxt/if_bnxt.c @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -1185,30 +1186,41 @@ return; } +static u_int +bnxt_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint8_t *mta = arg; + + if (cnt == BNXT_MAX_MC_ADDRS) + return (1); + + bcopy(LLADDR(sdl), &mta[cnt * ETHER_ADDR_LEN], ETHER_ADDR_LEN); + + return (1); +} + static void bnxt_multi_set(if_ctx_t ctx) { struct bnxt_softc *softc = iflib_get_softc(ctx); if_t ifp = iflib_get_ifp(ctx); uint8_t *mta; - int cnt, mcnt; + int mcnt; - mcnt = if_multiaddr_count(ifp, -1); + mta = softc->vnic_info.mc_list.idi_vaddr; + bzero(mta, softc->vnic_info.mc_list.idi_size); + mcnt = if_foreach_llmaddr(ifp, bnxt_copy_maddr, mta); if (mcnt > BNXT_MAX_MC_ADDRS) { softc->vnic_info.rx_mask |= HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_ALL_MCAST; bnxt_hwrm_cfa_l2_set_rx_mask(softc, &softc->vnic_info); - } - else { + } else { softc->vnic_info.rx_mask &= ~HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_ALL_MCAST; - mta = softc->vnic_info.mc_list.idi_vaddr; - bzero(mta, softc->vnic_info.mc_list.idi_size); - if_multiaddr_array(ifp, mta, &cnt, mcnt); bus_dmamap_sync(softc->vnic_info.mc_list.idi_tag, softc->vnic_info.mc_list.idi_map, BUS_DMASYNC_PREWRITE); - softc->vnic_info.mc_list_count = cnt; + softc->vnic_info.mc_list_count = mcnt; softc->vnic_info.rx_mask |= HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_MCAST; if (bnxt_hwrm_cfa_l2_set_rx_mask(softc, &softc->vnic_info)) @@ -1370,7 +1382,7 @@ int rc; if (ifp->if_flags & IFF_ALLMULTI || - if_multiaddr_count(ifp, -1) > BNXT_MAX_MC_ADDRS) + if_llmaddr_count(ifp) > BNXT_MAX_MC_ADDRS) softc->vnic_info.rx_mask |= HWRM_CFA_L2_SET_RX_MASK_INPUT_MASK_ALL_MCAST; else Index: sys/dev/bxe/bxe.h =================================================================== --- sys/dev/bxe/bxe.h +++ sys/dev/bxe/bxe.h @@ -1492,29 +1492,8 @@ #define BXE_STATS_UNLOCK(sc) mtx_unlock(&sc->stats_mtx) #define BXE_STATS_LOCK_ASSERT(sc) mtx_assert(&sc->stats_mtx, MA_OWNED) -#if __FreeBSD_version < 800000 -#define BXE_MCAST_LOCK(sc) \ - do { \ - mtx_lock(&sc->mcast_mtx); \ - IF_ADDR_LOCK(sc->ifp); \ - } while (0) -#define BXE_MCAST_UNLOCK(sc) \ - do { \ - IF_ADDR_UNLOCK(sc->ifp); \ - mtx_unlock(&sc->mcast_mtx); \ - } while (0) -#else -#define BXE_MCAST_LOCK(sc) \ - do { \ - mtx_lock(&sc->mcast_mtx); \ - if_maddr_rlock(sc->ifp); \ - } while (0) -#define BXE_MCAST_UNLOCK(sc) \ - do { \ - if_maddr_runlock(sc->ifp); \ - mtx_unlock(&sc->mcast_mtx); \ - } while (0) -#endif +#define BXE_MCAST_LOCK(sc) mtx_lock(&sc->mcast_mtx); +#define BXE_MCAST_UNLOCK(sc) mtx_unlock(&sc->mcast_mtx); #define BXE_MCAST_LOCK_ASSERT(sc) mtx_assert(&sc->mcast_mtx, MA_OWNED) int dmae_ready; Index: sys/dev/bxe/bxe.c =================================================================== --- sys/dev/bxe/bxe.c +++ sys/dev/bxe/bxe.c @@ -12065,27 +12065,31 @@ return (rc); } -/* must be called under IF_ADDR_LOCK */ +static u_int +bxe_push_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct ecore_mcast_list_elem *mc_mac = arg; + + mc_mac += cnt; + mc_mac->mac = (uint8_t *)LLADDR(sdl); + + return (1); +} + static int bxe_init_mcast_macs_list(struct bxe_softc *sc, struct ecore_mcast_ramrod_params *p) { if_t ifp = sc->ifp; - int mc_count = 0; - struct ifmultiaddr *ifma; + int mc_count; struct ecore_mcast_list_elem *mc_mac; - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) { - continue; - } - - mc_count++; - } - ECORE_LIST_INIT(&p->mcast_list); p->mcast_list_len = 0; + /* XXXGL: multicast count may change later */ + mc_count = if_llmaddr_count(ifp); + if (!mc_count) { return (0); } @@ -12097,20 +12101,15 @@ return (-1); } bzero(mc_mac, (sizeof(*mc_mac) * mc_count)); + if_foreach_llmaddr(ifp, bxe_push_maddr, mc_mac); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) { - continue; - } - - mc_mac->mac = (uint8_t *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); - ECORE_LIST_PUSH_TAIL(&mc_mac->link, &p->mcast_list); - + for (int i = 0; i < mc_count; i ++) { + ECORE_LIST_PUSH_TAIL(&mc_mac[i].link, &p->mcast_list); BLOGD(sc, DBG_LOAD, "Setting MCAST %02X:%02X:%02X:%02X:%02X:%02X and mc_count %d\n", - mc_mac->mac[0], mc_mac->mac[1], mc_mac->mac[2], - mc_mac->mac[3], mc_mac->mac[4], mc_mac->mac[5], mc_count); - mc_mac++; + mc_mac[i].mac[0], mc_mac[i].mac[1], mc_mac[i].mac[2], + mc_mac[i].mac[3], mc_mac[i].mac[4], mc_mac[i].mac[5], + mc_count); } p->mcast_list_len = mc_count; @@ -12171,69 +12170,59 @@ return (rc); } +struct bxe_set_addr_ctx { + struct bxe_softc *sc; + unsigned long ramrod_flags; + int rc; +}; + +static u_int +bxe_set_addr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct bxe_set_addr_ctx *ctx = arg; + struct ecore_vlan_mac_obj *mac_obj = &ctx->sc->sp_objs->mac_obj; + int rc; + + if (ctx->rc < 0) + return (0); + + rc = bxe_set_mac_one(ctx->sc, (uint8_t *)LLADDR(sdl), mac_obj, TRUE, + ECORE_UC_LIST_MAC, &ctx->ramrod_flags); + + /* do not treat adding same MAC as an error */ + if (rc == -EEXIST) + BLOGD(ctx->sc, DBG_SP, "Failed to schedule ADD operations (EEXIST)\n"); + else if (rc < 0) { + BLOGE(ctx->sc, "Failed to schedule ADD operations (%d)\n", rc); + ctx->rc = rc; + } + + return (1); +} + static int bxe_set_uc_list(struct bxe_softc *sc) { if_t ifp = sc->ifp; struct ecore_vlan_mac_obj *mac_obj = &sc->sp_objs->mac_obj; - struct ifaddr *ifa; - unsigned long ramrod_flags = 0; + struct bxe_set_addr_ctx ctx = { sc, 0, 0 }; int rc; -#if __FreeBSD_version < 800000 - IF_ADDR_LOCK(ifp); -#else - if_addr_rlock(ifp); -#endif - /* first schedule a cleanup up of old configuration */ rc = bxe_del_all_macs(sc, mac_obj, ECORE_UC_LIST_MAC, FALSE); if (rc < 0) { BLOGE(sc, "Failed to schedule delete of all ETH MACs (%d)\n", rc); -#if __FreeBSD_version < 800000 - IF_ADDR_UNLOCK(ifp); -#else - if_addr_runlock(ifp); -#endif return (rc); } - ifa = if_getifaddr(ifp); /* XXX Is this structure */ - while (ifa) { - if (ifa->ifa_addr->sa_family != AF_LINK) { - ifa = CK_STAILQ_NEXT(ifa, ifa_link); - continue; - } - - rc = bxe_set_mac_one(sc, (uint8_t *)LLADDR((struct sockaddr_dl *)ifa->ifa_addr), - mac_obj, TRUE, ECORE_UC_LIST_MAC, &ramrod_flags); - if (rc == -EEXIST) { - BLOGD(sc, DBG_SP, "Failed to schedule ADD operations (EEXIST)\n"); - /* do not treat adding same MAC as an error */ - rc = 0; - } else if (rc < 0) { - BLOGE(sc, "Failed to schedule ADD operations (%d)\n", rc); -#if __FreeBSD_version < 800000 - IF_ADDR_UNLOCK(ifp); -#else - if_addr_runlock(ifp); -#endif - return (rc); - } - - ifa = CK_STAILQ_NEXT(ifa, ifa_link); - } - -#if __FreeBSD_version < 800000 - IF_ADDR_UNLOCK(ifp); -#else - if_addr_runlock(ifp); -#endif + if_foreach_lladdr(ifp, bxe_set_addr, &ctx); + if (ctx.rc < 0) + return (ctx.rc); /* Execute the pending commands */ - bit_set(&ramrod_flags, RAMROD_CONT); + bit_set(&ctx.ramrod_flags, RAMROD_CONT); return (bxe_set_mac_one(sc, NULL, mac_obj, FALSE /* don't care */, - ECORE_UC_LIST_MAC, &ramrod_flags)); + ECORE_UC_LIST_MAC, &ctx.ramrod_flags)); } static void Index: sys/dev/cadence/if_cgem.c =================================================================== --- sys/dev/cadence/if_cgem.c +++ sys/dev/cadence/if_cgem.c @@ -299,6 +299,21 @@ return hash; } +static u_int +cgem_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *hashes = arg; + int index; + + index = cgem_mac_hash(LLADDR(sdl)); + if (index > 31) + hashes[0] |= (1 << (index - 32)); + else + hashes[1] |= (1 << index); + + return (1); +} + /* After any change in rx flags or multi-cast addresses, set up * hash registers and net config register bits. */ @@ -306,15 +321,9 @@ cgem_rx_filter(struct cgem_softc *sc) { if_t ifp = sc->ifp; - u_char *mta; - - int index, i, mcnt; - uint32_t hash_hi, hash_lo; + uint32_t hashes[2] = { 0, 0 }; uint32_t net_cfg; - hash_hi = 0; - hash_lo = 0; - net_cfg = RD4(sc, CGEM_NET_CFG); net_cfg &= ~(CGEM_NET_CFG_MULTI_HASH_EN | @@ -327,36 +336,17 @@ if ((if_getflags(ifp) & IFF_BROADCAST) == 0) net_cfg |= CGEM_NET_CFG_NO_BCAST; if ((if_getflags(ifp) & IFF_ALLMULTI) != 0) { - hash_hi = 0xffffffff; - hash_lo = 0xffffffff; - } else { - mcnt = if_multiaddr_count(ifp, -1); - mta = malloc(ETHER_ADDR_LEN * mcnt, M_DEVBUF, - M_NOWAIT); - if (mta == NULL) { - device_printf(sc->dev, - "failed to allocate temp mcast list\n"); - return; - } - if_multiaddr_array(ifp, mta, &mcnt, mcnt); - for (i = 0; i < mcnt; i++) { - index = cgem_mac_hash( - LLADDR((struct sockaddr_dl *) - (mta + (i * ETHER_ADDR_LEN)))); - if (index > 31) - hash_hi |= (1 << (index - 32)); - else - hash_lo |= (1 << index); - } - free(mta, M_DEVBUF); - } + hashes[0] = 0xffffffff; + hashes[1] = 0xffffffff; + } else + if_foreach_llmaddr(ifp, cgem_hash_maddr, hashes); - if (hash_hi != 0 || hash_lo != 0) + if (hashes[0] != 0 || hashes[1] != 0) net_cfg |= CGEM_NET_CFG_MULTI_HASH_EN; } - WR4(sc, CGEM_HASH_TOP, hash_hi); - WR4(sc, CGEM_HASH_BOT, hash_lo); + WR4(sc, CGEM_HASH_TOP, hashes[0]); + WR4(sc, CGEM_HASH_BOT, hashes[1]); WR4(sc, CGEM_NET_CFG, net_cfg); } Index: sys/dev/cas/if_cas.c =================================================================== --- sys/dev/cas/if_cas.c +++ sys/dev/cas/if_cas.c @@ -2498,14 +2498,27 @@ return (error); } +static u_int +cas_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t crc, *hash = arg; + + crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN); + /* We just want the 8 most significant bits. */ + crc >>= 24; + /* Set the corresponding bit in the filter. */ + hash[crc >> 4] |= 1 << (15 - (crc & 15)); + + return (1); +} + static void cas_setladrf(struct cas_softc *sc) { struct ifnet *ifp = sc->sc_ifp; - struct ifmultiaddr *inm; int i; uint32_t hash[16]; - uint32_t crc, v; + uint32_t v; CAS_LOCK_ASSERT(sc, MA_OWNED); @@ -2542,23 +2555,8 @@ * is the MSB). */ - /* Clear the hash table. */ memset(hash, 0, sizeof(hash)); - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(inm, &ifp->if_multiaddrs, ifma_link) { - if (inm->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) - inm->ifma_addr), ETHER_ADDR_LEN); - - /* We just want the 8 most significant bits. */ - crc >>= 24; - - /* Set the corresponding bit in the filter. */ - hash[crc >> 4] |= 1 << (15 - (crc & 15)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, cas_hash_maddr, &hash); v |= CAS_MAC_RX_CONF_HFILTER; Index: sys/dev/cxgb/common/cxgb_xgmac.c =================================================================== --- sys/dev/cxgb/common/cxgb_xgmac.c +++ sys/dev/cxgb/common/cxgb_xgmac.c @@ -408,9 +408,32 @@ * Configures the MAC Rx mode (promiscuity, etc) and exact and hash * address filters. */ +struct t3_mcaddr_ctx { + struct cmac *mac; + u32 hash_lo, hash_hi; +}; + +static u_int +t3_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct t3_mcaddr_ctx *ctx = arg; + int hash; + + if (ctx->mac->nucast + cnt < EXACT_ADDR_FILTERS) + set_addr_filter(ctx->mac, ctx->mac->nucast + cnt, LLADDR(sdl)); + else { + hash = hash_hw_addr(LLADDR(sdl)); + if (hash < 32) + ctx->hash_lo |= (1 << hash); + else + ctx->hash_hi |= (1 << (hash - 32)); + } + return (1); +} + int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm) { - u32 hash_lo, hash_hi; + struct t3_mcaddr_ctx ctx; adapter_t *adap = mac->adapter; unsigned int oft = mac->offset; @@ -422,27 +445,15 @@ mac->promisc_map ? F_COPYALLFRAMES : 0); if (allmulti_rx_mode(rm) || mac->multiport) - hash_lo = hash_hi = 0xffffffff; + ctx.hash_lo = ctx.hash_hi = 0xffffffff; else { - u8 *addr; - int exact_addr_idx = mac->nucast; - - hash_lo = hash_hi = 0; - while ((addr = t3_get_next_mcaddr(rm))) - if (exact_addr_idx < EXACT_ADDR_FILTERS) - set_addr_filter(mac, exact_addr_idx++, addr); - else { - int hash = hash_hw_addr(addr); - - if (hash < 32) - hash_lo |= (1 << hash); - else - hash_hi |= (1 << (hash - 32)); - } + ctx.mac = mac; + ctx.hash_lo = ctx.hash_hi = 0; + if_foreach_llmaddr(rm->port->ifp, t3_hash_maddr, &ctx); } - t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo); - t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi); + t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, ctx.hash_lo); + t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, ctx.hash_hi); return 0; } Index: sys/dev/cxgb/cxgb_adapter.h =================================================================== --- sys/dev/cxgb/cxgb_adapter.h +++ sys/dev/cxgb/cxgb_adapter.h @@ -463,30 +463,6 @@ pci_write_config(adapter->dev, reg, val, 2); } -static __inline uint8_t * -t3_get_next_mcaddr(struct t3_rx_mode *rm) -{ - uint8_t *macaddr = NULL; - struct ifnet *ifp = rm->port->ifp; - struct ifmultiaddr *ifma; - int i = 0; - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (i == rm->idx) { - macaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); - break; - } - i++; - } - if_maddr_runlock(ifp); - - rm->idx++; - return (macaddr); -} - static __inline void t3_init_rx_mode(struct t3_rx_mode *rm, struct port_info *port) { Index: sys/dev/cxgbe/t4_main.c =================================================================== --- sys/dev/cxgbe/t4_main.c +++ sys/dev/cxgbe/t4_main.c @@ -4784,6 +4784,54 @@ } #define FW_MAC_EXACT_CHUNK 7 +struct mcaddr_ctx { + struct ifnet *ifp; + const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; + uint64_t hash; + int i; + int del; + int rc; +}; + +static u_int +add_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct mcaddr_ctx *ctx = arg; + struct vi_info *vi = ctx->ifp->if_softc; + struct port_info *pi = vi->pi; + struct adapter *sc = pi->adapter; + + if (ctx->rc < 0) + return (0); + + ctx->mcaddr[ctx->i] = LLADDR(sdl); + MPASS(ETHER_IS_MULTICAST(ctx->mcaddr[ctx->i])); + ctx->i++; + + if (ctx->i == FW_MAC_EXACT_CHUNK) { + ctx->rc = t4_alloc_mac_filt(sc, sc->mbox, vi->viid, ctx->del, + ctx->i, ctx->mcaddr, NULL, &ctx->hash, 0); + if (ctx->rc < 0) { + int j; + + for (j = 0; j < ctx->i; j++) { + if_printf(ctx->ifp, + "failed to add mc address" + " %02x:%02x:%02x:" + "%02x:%02x:%02x rc=%d\n", + ctx->mcaddr[j][0], ctx->mcaddr[j][1], + ctx->mcaddr[j][2], ctx->mcaddr[j][3], + ctx->mcaddr[j][4], ctx->mcaddr[j][5], + -ctx->rc); + } + return (0); + } + ctx->del = 0; + ctx->i = 0; + } + + return (1); +} /* * Program the port's XGMAC based on parameters in ifnet. The caller also @@ -4840,66 +4888,51 @@ } if (flags & XGMAC_MCADDRS) { - const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; - int del = 1; - uint64_t hash = 0; - struct ifmultiaddr *ifma; - int i = 0, j; - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - mcaddr[i] = - LLADDR((struct sockaddr_dl *)ifma->ifma_addr); - MPASS(ETHER_IS_MULTICAST(mcaddr[i])); - i++; - - if (i == FW_MAC_EXACT_CHUNK) { - rc = t4_alloc_mac_filt(sc, sc->mbox, vi->viid, - del, i, mcaddr, NULL, &hash, 0); - if (rc < 0) { - rc = -rc; - for (j = 0; j < i; j++) { - if_printf(ifp, - "failed to add mc address" - " %02x:%02x:%02x:" - "%02x:%02x:%02x rc=%d\n", - mcaddr[j][0], mcaddr[j][1], - mcaddr[j][2], mcaddr[j][3], - mcaddr[j][4], mcaddr[j][5], - rc); - } - goto mcfail; - } - del = 0; - i = 0; - } + struct epoch_tracker et; + struct mcaddr_ctx ctx; + int j; + + ctx.ifp = ifp; + ctx.hash = 0; + ctx.i = 0; + ctx.del = 1; + /* + * Unlike other drivers, we accumulate list of pointers into + * interface address lists and we need to keep it safe even + * after if_foreach_llmaddr() returns, thus we must enter the + * network epoch. + */ + NET_EPOCH_ENTER(et); + if_foreach_llmaddr(ifp, add_maddr, &ctx); + if (ctx.rc < 0) { + NET_EPOCH_EXIT(et); + rc = -ctx.rc; + return (rc); } - if (i > 0) { - rc = t4_alloc_mac_filt(sc, sc->mbox, vi->viid, del, i, - mcaddr, NULL, &hash, 0); + if (ctx.i > 0) { + rc = t4_alloc_mac_filt(sc, sc->mbox, vi->viid, + ctx.del, ctx.i, ctx.mcaddr, NULL, &ctx.hash, 0); + NET_EPOCH_EXIT(et); if (rc < 0) { rc = -rc; - for (j = 0; j < i; j++) { + for (j = 0; j < ctx.i; j++) { if_printf(ifp, "failed to add mc address" " %02x:%02x:%02x:" "%02x:%02x:%02x rc=%d\n", - mcaddr[j][0], mcaddr[j][1], - mcaddr[j][2], mcaddr[j][3], - mcaddr[j][4], mcaddr[j][5], + ctx.mcaddr[j][0], ctx.mcaddr[j][1], + ctx.mcaddr[j][2], ctx.mcaddr[j][3], + ctx.mcaddr[j][4], ctx.mcaddr[j][5], rc); } - goto mcfail; + return (rc); } - } + } else + NET_EPOCH_EXIT(et); - rc = -t4_set_addr_hash(sc, sc->mbox, vi->viid, 0, hash, 0); + rc = -t4_set_addr_hash(sc, sc->mbox, vi->viid, 0, ctx.hash, 0); if (rc != 0) if_printf(ifp, "failed to set mc address hash: %d", rc); -mcfail: - if_maddr_runlock(ifp); } return (rc); Index: sys/dev/dc/if_dc.c =================================================================== --- sys/dev/dc/if_dc.c +++ sys/dev/dc/if_dc.c @@ -962,13 +962,24 @@ * frames. We also sneak the broadcast address into the hash filter since * we need that too. */ +static u_int +dc_hash_maddr_21143(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct dc_softc *sc = arg; + uint32_t h; + + h = dc_mchash_le(sc, LLADDR(sdl)); + sc->dc_cdata.dc_sbuf[h >> 4] |= htole32(1 << (h & 0xF)); + + return (1); +} + static void dc_setfilt_21143(struct dc_softc *sc) { uint16_t eaddr[(ETHER_ADDR_LEN+1)/2]; struct dc_desc *sframe; uint32_t h, *sp; - struct ifmultiaddr *ifma; struct ifnet *ifp; int i; @@ -998,15 +1009,7 @@ else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = dc_mchash_le(sc, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - sp[h >> 4] |= htole32(1 << (h & 0xF)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, dc_hash_maddr_21143, sp); if (ifp->if_flags & IFF_BROADCAST) { h = dc_mchash_le(sc, ifp->if_broadcastaddr); @@ -1036,14 +1039,47 @@ sc->dc_wdog_timer = 5; } +static u_int +dc_hash_maddr_admtek_be(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *hashes = arg; + int h = 0; + + h = dc_mchash_be(LLADDR(sdl)); + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + + return (1); +} + +struct dc_hash_maddr_admtek_le_ctx { + struct dc_softc *sc; + uint32_t hashes[2]; +}; + +static u_int +dc_hash_maddr_admtek_le(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct dc_hash_maddr_admtek_le_ctx *ctx = arg; + int h = 0; + + h = dc_mchash_le(ctx->sc, LLADDR(sdl)); + if (h < 32) + ctx->hashes[0] |= (1 << h); + else + ctx->hashes[1] |= (1 << (h - 32)); + + return (1); +} + static void dc_setfilt_admtek(struct dc_softc *sc) { uint8_t eaddr[ETHER_ADDR_LEN]; struct ifnet *ifp; - struct ifmultiaddr *ifma; - int h = 0; - uint32_t hashes[2] = { 0, 0 }; + struct dc_hash_maddr_admtek_le_ctx ctx = { sc, { 0, 0 }}; ifp = sc->dc_ifp; @@ -1076,25 +1112,13 @@ return; /* Now program new ones. */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (DC_IS_CENTAUR(sc)) - h = dc_mchash_le(sc, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - else - h = dc_mchash_be( - LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - } - if_maddr_runlock(ifp); + if (DC_IS_CENTAUR(sc)) + if_foreach_llmaddr(ifp, dc_hash_maddr_admtek_le, &ctx); + else + if_foreach_llmaddr(ifp, dc_hash_maddr_admtek_be, &ctx.hashes); - CSR_WRITE_4(sc, DC_AL_MAR0, hashes[0]); - CSR_WRITE_4(sc, DC_AL_MAR1, hashes[1]); + CSR_WRITE_4(sc, DC_AL_MAR0, ctx.hashes[0]); + CSR_WRITE_4(sc, DC_AL_MAR1, ctx.hashes[1]); } static void @@ -1102,8 +1126,6 @@ { uint32_t eaddr[(ETHER_ADDR_LEN+3)/4]; struct ifnet *ifp; - struct ifmultiaddr *ifma; - int h = 0; uint32_t hashes[2] = { 0, 0 }; ifp = sc->dc_ifp; @@ -1149,17 +1171,7 @@ return; /* now program new ones */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = dc_mchash_be(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, dc_hash_maddr_admtek_be, hashes); CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0); CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[0]); @@ -1167,15 +1179,29 @@ CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[1]); } +static u_int +dc_hash_maddr_uli(void *arg, struct sockaddr_dl *sdl, u_int mcnt) +{ + uint32_t **sp = arg; + uint8_t *ma; + + if (mcnt == DC_ULI_FILTER_NPERF) + return (0); + ma = LLADDR(sdl); + *(*sp)++ = DC_SP_MAC(ma[1] << 8 | ma[0]); + *(*sp)++ = DC_SP_MAC(ma[3] << 8 | ma[2]); + *(*sp)++ = DC_SP_MAC(ma[5] << 8 | ma[4]); + + return (1); +} + static void dc_setfilt_uli(struct dc_softc *sc) { uint8_t eaddr[ETHER_ADDR_LEN]; struct ifnet *ifp; - struct ifmultiaddr *ifma; struct dc_desc *sframe; uint32_t filter, *sp; - uint8_t *ma; int i, mcnt; ifp = sc->dc_ifp; @@ -1209,28 +1235,16 @@ filter &= ~(DC_NETCFG_RX_PROMISC | DC_NETCFG_RX_ALLMULTI); /* Now build perfect filters. */ - mcnt = 0; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (mcnt >= DC_ULI_FILTER_NPERF) { - filter |= DC_NETCFG_RX_ALLMULTI; - break; - } - ma = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); - *sp++ = DC_SP_MAC(ma[1] << 8 | ma[0]); - *sp++ = DC_SP_MAC(ma[3] << 8 | ma[2]); - *sp++ = DC_SP_MAC(ma[5] << 8 | ma[4]); - mcnt++; - } - if_maddr_runlock(ifp); + mcnt = if_foreach_llmaddr(ifp, dc_hash_maddr_uli, &sp); - for (; mcnt < DC_ULI_FILTER_NPERF; mcnt++) { - *sp++ = DC_SP_MAC(0xFFFF); - *sp++ = DC_SP_MAC(0xFFFF); - *sp++ = DC_SP_MAC(0xFFFF); - } + if (mcnt == DC_ULI_FILTER_NPERF) + filter |= DC_NETCFG_RX_ALLMULTI; + else + for (; mcnt < DC_ULI_FILTER_NPERF; mcnt++) { + *sp++ = DC_SP_MAC(0xFFFF); + *sp++ = DC_SP_MAC(0xFFFF); + *sp++ = DC_SP_MAC(0xFFFF); + } if (filter & (DC_NETCFG_TX_ON | DC_NETCFG_RX_ON)) CSR_WRITE_4(sc, DC_NETCFG, @@ -1258,12 +1272,22 @@ sc->dc_wdog_timer = 5; } +static u_int +dc_hash_maddr_xircom(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct dc_softc *sc = arg; + uint32_t h; + + h = dc_mchash_le(sc, LLADDR(sdl)); + sc->dc_cdata.dc_sbuf[h >> 4] |= htole32(1 << (h & 0xF)); + return (1); +} + static void dc_setfilt_xircom(struct dc_softc *sc) { uint16_t eaddr[(ETHER_ADDR_LEN+1)/2]; struct ifnet *ifp; - struct ifmultiaddr *ifma; struct dc_desc *sframe; uint32_t h, *sp; int i; @@ -1295,15 +1319,7 @@ else DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = dc_mchash_le(sc, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - sp[h >> 4] |= htole32(1 << (h & 0xF)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, dc_hash_maddr_xircom, &sp); if (ifp->if_flags & IFF_BROADCAST) { h = dc_mchash_le(sc, ifp->if_broadcastaddr); Index: sys/dev/dwc/if_dwc.c =================================================================== --- sys/dev/dwc/if_dwc.c +++ sys/dev/dwc/if_dwc.c @@ -581,13 +581,37 @@ return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4]; } +struct dwc_hash_maddr_ctx { + struct dwc_softc *sc; + uint32_t hash[8]; +}; + +static u_int +dwc_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct dwc_hash_maddr_ctx *ctx = arg; + uint32_t crc, hashbit, hashreg; + uint8_t val; + + crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN); + /* Take lower 8 bits and reverse it */ + val = bitreverse(~crc & 0xff); + if (ctx->sc->mactype == DWC_GMAC_ALT_DESC) + val >>= 2; /* Only need lower 6 bits */ + hashreg = (val >> 5); + hashbit = (val & 31); + ctx->hash[hashreg] |= (1 << hashbit); + + return (1); +} + static void dwc_setup_rxfilter(struct dwc_softc *sc) { - struct ifmultiaddr *ifma; + struct dwc_hash_maddr_ctx ctx; struct ifnet *ifp; - uint8_t *eaddr, val; - uint32_t crc, ffval, hashbit, hashreg, hi, lo, hash[8]; + uint8_t *eaddr; + uint32_t ffval, hi, lo; int nhash, i; DWC_ASSERT_LOCKED(sc); @@ -601,27 +625,13 @@ if ((ifp->if_flags & IFF_ALLMULTI) != 0) { ffval = (FRAME_FILTER_PM); for (i = 0; i < nhash; i++) - hash[i] = ~0; + ctx.hash[i] = ~0; } else { ffval = (FRAME_FILTER_HMC); for (i = 0; i < nhash; i++) - hash[i] = 0; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - - /* Take lower 8 bits and reverse it */ - val = bitreverse(~crc & 0xff); - if (sc->mactype == DWC_GMAC_ALT_DESC) - val >>= nhash; /* Only need lower 6 bits */ - hashreg = (val >> 5); - hashbit = (val & 31); - hash[hashreg] |= (1 << hashbit); - } - if_maddr_runlock(ifp); + ctx.hash[i] = 0; + ctx.sc = sc; + if_foreach_llmaddr(ifp, dwc_hash_maddr, &ctx); } /* @@ -641,11 +651,11 @@ WRITE4(sc, MAC_ADDRESS_HIGH(0), hi); WRITE4(sc, MAC_FRAME_FILTER, ffval); if (sc->mactype == DWC_GMAC_ALT_DESC) { - WRITE4(sc, GMAC_MAC_HTLOW, hash[0]); - WRITE4(sc, GMAC_MAC_HTHIGH, hash[1]); + WRITE4(sc, GMAC_MAC_HTLOW, ctx.hash[0]); + WRITE4(sc, GMAC_MAC_HTHIGH, ctx.hash[1]); } else { for (i = 0; i < nhash; i++) - WRITE4(sc, HASH_TABLE_REG(i), hash[i]); + WRITE4(sc, HASH_TABLE_REG(i), ctx.hash[i]); } } Index: sys/dev/e1000/if_em.c =================================================================== --- sys/dev/e1000/if_em.c +++ sys/dev/e1000/if_em.c @@ -1656,7 +1656,7 @@ if (if_getflags(ifp) & IFF_ALLMULTI) mcnt = MAX_NUM_MULTICAST_ADDRESSES; else - mcnt = if_multiaddr_count(ifp, MAX_NUM_MULTICAST_ADDRESSES); + mcnt = if_llmaddr_count(ifp); /* Don't disable if in MAX groups */ if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) reg_rctl &= (~E1000_RCTL_MPE); @@ -1665,6 +1665,19 @@ } +static u_int +em_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + u8 *mta = arg; + + if (cnt == MAX_NUM_MULTICAST_ADDRESSES) + return (1); + + bcopy(LLADDR(sdl), &mta[cnt * ETH_ADDR_LEN], ETH_ADDR_LEN); + + return (1); +} + /********************************************************************* * Multicast Update * @@ -1696,7 +1709,7 @@ msec_delay(5); } - if_multiaddr_array(ifp, mta, &mcnt, MAX_NUM_MULTICAST_ADDRESSES); + mcnt = if_foreach_llmaddr(ifp, em_copy_maddr, mta); if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES) { reg_rctl = E1000_READ_REG(&adapter->hw, E1000_RCTL); Index: sys/dev/et/if_et.c =================================================================== --- sys/dev/et/if_et.c +++ sys/dev/et/if_et.c @@ -1560,13 +1560,36 @@ } } +static u_int +et_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t h, *hp, *hash = arg; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); + h = (h & 0x3f800000) >> 23; + + hp = &hash[0]; + if (h >= 32 && h < 64) { + h -= 32; + hp = &hash[1]; + } else if (h >= 64 && h < 96) { + h -= 64; + hp = &hash[2]; + } else if (h >= 96) { + h -= 96; + hp = &hash[3]; + } + *hp |= (1 << h); + + return (1); +} + static void et_setmulti(struct et_softc *sc) { struct ifnet *ifp; uint32_t hash[4] = { 0, 0, 0, 0 }; uint32_t rxmac_ctrl, pktfilt; - struct ifmultiaddr *ifma; int i, count; ET_LOCK_ASSERT(sc); @@ -1581,34 +1604,7 @@ goto back; } - count = 0; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - uint32_t *hp, h; - - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - h = (h & 0x3f800000) >> 23; - - hp = &hash[0]; - if (h >= 32 && h < 64) { - h -= 32; - hp = &hash[1]; - } else if (h >= 64 && h < 96) { - h -= 64; - hp = &hash[2]; - } else if (h >= 96) { - h -= 96; - hp = &hash[3]; - } - *hp |= (1 << h); - - ++count; - } - if_maddr_runlock(ifp); + count = if_foreach_llmaddr(ifp, et_hash_maddr, &hash); for (i = 0; i < 4; ++i) CSR_WRITE_4(sc, ET_MULTI_HASH + (i * 4), hash[i]); Index: sys/dev/ffec/if_ffec.c =================================================================== --- sys/dev/ffec/if_ffec.c +++ sys/dev/ffec/if_ffec.c @@ -974,13 +974,24 @@ } } +static u_int +ffec_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint64_t *ghash = arg; + uint32_t crc; + + /* 6 bits from MSB in LE CRC32 are used for hash. */ + crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN); + *ghash |= 1LLU << (((uint8_t *)&crc)[3] >> 2); + + return (1); +} + static void ffec_setup_rxfilter(struct ffec_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; uint8_t *eaddr; - uint32_t crc; uint64_t ghash, ihash; FFEC_ASSERT_LOCKED(sc); @@ -994,16 +1005,7 @@ ghash = 0xffffffffffffffffLLU; else { ghash = 0; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - /* 6 bits from MSB in LE CRC32 are used for hash. */ - crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - ghash |= 1LLU << (((uint8_t *)&crc)[3] >> 2); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, ffec_hash_maddr, &ghash); } WR4(sc, FEC_GAUR_REG, (uint32_t)(ghash >> 32)); WR4(sc, FEC_GALR_REG, (uint32_t)ghash); Index: sys/dev/fxp/if_fxp.c =================================================================== --- sys/dev/fxp/if_fxp.c +++ sys/dev/fxp/if_fxp.c @@ -245,7 +245,7 @@ struct fxp_rx *rxp); static int fxp_new_rfabuf(struct fxp_softc *sc, struct fxp_rx *rxp); -static int fxp_mc_addrs(struct fxp_softc *sc); +static void fxp_mc_addrs(struct fxp_softc *sc); static void fxp_mc_setup(struct fxp_softc *sc); static uint16_t fxp_eeprom_getword(struct fxp_softc *sc, int offset, int autosize); @@ -2976,27 +2976,37 @@ return (error); } +static u_int +fxp_setup_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct fxp_softc *sc = arg; + struct fxp_cb_mcs *mcsp = sc->mcsp; + + if (mcsp->mc_cnt < MAXMCADDR) + bcopy(LLADDR(sdl), mcsp->mc_addr[mcsp->mc_cnt * ETHER_ADDR_LEN], + ETHER_ADDR_LEN); + mcsp->mc_cnt++; + return (1); +} + /* * Fill in the multicast address list and return number of entries. */ -static int +static void fxp_mc_addrs(struct fxp_softc *sc) { struct fxp_cb_mcs *mcsp = sc->mcsp; if_t ifp = sc->ifp; - int nmcasts = 0; if ((if_getflags(ifp) & IFF_ALLMULTI) == 0) { - if_maddr_rlock(ifp); - if_setupmultiaddr(ifp, mcsp->mc_addr, &nmcasts, MAXMCADDR); - if (nmcasts >= MAXMCADDR) { + mcsp->mc_cnt = 0; + if_foreach_llmaddr(sc->ifp, fxp_setup_maddr, sc); + if (mcsp->mc_cnt >= MAXMCADDR) { if_setflagbits(ifp, IFF_ALLMULTI, 0); - nmcasts = 0; + mcsp->mc_cnt = 0; } - if_maddr_runlock(ifp); } - mcsp->mc_cnt = htole16(nmcasts * ETHER_ADDR_LEN); - return (nmcasts); + mcsp->mc_cnt = htole16(mcsp->mc_cnt * ETHER_ADDR_LEN); } /* Index: sys/dev/gem/if_gem.c =================================================================== --- sys/dev/gem/if_gem.c +++ sys/dev/gem/if_gem.c @@ -2202,14 +2202,27 @@ return (error); } +static u_int +gem_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t crc, *hash = arg; + + crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN); + /* We just want the 8 most significant bits. */ + crc >>= 24; + /* Set the corresponding bit in the filter. */ + hash[crc >> 4] |= 1 << (15 - (crc & 15)); + + return (1); +} + static void gem_setladrf(struct gem_softc *sc) { struct ifnet *ifp = sc->sc_ifp; - struct ifmultiaddr *inm; int i; uint32_t hash[16]; - uint32_t crc, v; + uint32_t v; GEM_LOCK_ASSERT(sc, MA_OWNED); @@ -2245,23 +2258,8 @@ * is the MSB). */ - /* Clear the hash table. */ memset(hash, 0, sizeof(hash)); - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(inm, &ifp->if_multiaddrs, ifma_link) { - if (inm->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) - inm->ifma_addr), ETHER_ADDR_LEN); - - /* We just want the 8 most significant bits. */ - crc >>= 24; - - /* Set the corresponding bit in the filter. */ - hash[crc >> 4] |= 1 << (15 - (crc & 15)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, gem_hash_maddr, hash); v |= GEM_MAC_RX_HASH_FILTER; Index: sys/dev/hme/if_hme.c =================================================================== --- sys/dev/hme/if_hme.c +++ sys/dev/hme/if_hme.c @@ -1656,6 +1656,20 @@ return (error); } +static u_int +hme_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t crc, *hash = arg; + + crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN); + /* Just want the 6 most significant bits. */ + crc >>= 26; + /* Set the corresponding bit in the filter. */ + hash[crc >> 4] |= 1 << (crc & 0xf); + + return (1); +} + /* * Set up the logical address filter. */ @@ -1663,8 +1677,6 @@ hme_setladrf(struct hme_softc *sc, int reenable) { struct ifnet *ifp = sc->sc_ifp; - struct ifmultiaddr *inm; - u_int32_t crc; u_int32_t hash[4]; u_int32_t macc; @@ -1721,21 +1733,7 @@ * selects the word, while the rest of the bits select the bit within * the word. */ - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(inm, &ifp->if_multiaddrs, ifma_link) { - if (inm->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) - inm->ifma_addr), ETHER_ADDR_LEN); - - /* Just want the 6 most significant bits. */ - crc >>= 26; - - /* Set the corresponding bit in the filter. */ - hash[crc >> 4] |= 1 << (crc & 0xf); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, hme_hash_maddr, &hash); chipit: /* Now load the hash table into the chip */ Index: sys/dev/if_ndis/if_ndis.c =================================================================== --- sys/dev/if_ndis/if_ndis.c +++ sys/dev/if_ndis/if_ndis.c @@ -282,6 +282,22 @@ return (error); } +struct mclist_ctx { + uint8_t *mclist; + int mclistsz; +}; + +static u_int +ndis_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct mclist_ctx *ctx = arg; + + if (cnt < ctx->mclistsz) + bcopy(LLADDR(sdl), ctx->mclist + (ETHER_ADDR_LEN * cnt), + ETHER_ADDR_LEN); + return (1); +} + /* * Program the 64-bit multicast hash filter. */ @@ -290,9 +306,8 @@ struct ndis_softc *sc; { struct ifnet *ifp; - struct ifmultiaddr *ifma; - int len, mclistsz, error; - uint8_t *mclist; + struct mclist_ctx ctx; + int len, error; if (!NDIS_INITIALIZED(sc)) @@ -313,40 +328,31 @@ return; } - if (CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) + if (if_llmaddr_count(ifp) == 0) return; - len = sizeof(mclistsz); - ndis_get_info(sc, OID_802_3_MAXIMUM_LIST_SIZE, &mclistsz, &len); + len = sizeof(ctx.mclistsz); + ndis_get_info(sc, OID_802_3_MAXIMUM_LIST_SIZE, &ctx.mclistsz, &len); - mclist = malloc(ETHER_ADDR_LEN * mclistsz, M_TEMP, M_NOWAIT|M_ZERO); + ctx.mclist = malloc(ETHER_ADDR_LEN * ctx.mclistsz, M_TEMP, + M_NOWAIT | M_ZERO); - if (mclist == NULL) { + if (ctx.mclist == NULL) { sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; goto out; } sc->ndis_filter |= NDIS_PACKET_TYPE_MULTICAST; - len = 0; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - mclist + (ETHER_ADDR_LEN * len), ETHER_ADDR_LEN); - len++; - if (len > mclistsz) { - if_maddr_runlock(ifp); - sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; - sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST; + len = if_foreach_llmaddr(ifp, ndis_copy_maddr, &ctx); + if (len > ctx.mclistsz) { + sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; + sc->ndis_filter &= ~NDIS_PACKET_TYPE_MULTICAST; goto out; - } } - if_maddr_runlock(ifp); len = len * ETHER_ADDR_LEN; - error = ndis_set_info(sc, OID_802_3_MULTICAST_LIST, mclist, &len); + error = ndis_set_info(sc, OID_802_3_MULTICAST_LIST, ctx.mclist, &len); if (error) { device_printf(sc->ndis_dev, "set mclist failed: %d\n", error); sc->ndis_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; @@ -354,7 +360,7 @@ } out: - free(mclist, M_TEMP); + free(ctx.mclist, M_TEMP); len = sizeof(sc->ndis_filter); error = ndis_set_info(sc, OID_GEN_CURRENT_PACKET_FILTER, Index: sys/dev/ixgbe/if_ix.c =================================================================== --- sys/dev/ixgbe/if_ix.c +++ sys/dev/ixgbe/if_ix.c @@ -2333,7 +2333,7 @@ if (ifp->if_flags & IFF_ALLMULTI) mcnt = MAX_NUM_MULTICAST_ADDRESSES; else { - mcnt = if_multiaddr_count(ifp, MAX_NUM_MULTICAST_ADDRESSES); + mcnt = min(if_llmaddr_count(ifp), MAX_NUM_MULTICAST_ADDRESSES); } if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) rctl &= (~IXGBE_FCTRL_MPE); @@ -3207,18 +3207,15 @@ * * Called whenever multicast address list is updated. ************************************************************************/ -static int -ixgbe_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int count) +static u_int +ixgbe_mc_filter_apply(void *arg, struct sockaddr_dl *sdl, u_int count) { struct adapter *adapter = arg; struct ixgbe_mc_addr *mta = adapter->mta; - if (ifma->ifma_addr->sa_family != AF_LINK) - return (0); if (count == MAX_NUM_MULTICAST_ADDRESSES) return (0); - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - mta[count].addr, IXGBE_ETH_LENGTH_OF_ADDRESS); + bcopy(LLADDR(sdl), mta[count].addr, IXGBE_ETH_LENGTH_OF_ADDRESS); mta[count].vmdq = adapter->pool; return (1); @@ -3231,15 +3228,16 @@ struct ixgbe_mc_addr *mta; struct ifnet *ifp = iflib_get_ifp(ctx); u8 *update_ptr; - int mcnt = 0; u32 fctrl; + u_int mcnt; IOCTL_DEBUGOUT("ixgbe_if_multi_set: begin"); mta = adapter->mta; bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES); - mcnt = if_multi_apply(iflib_get_ifp(ctx), ixgbe_mc_filter_apply, adapter); + mcnt = if_foreach_llmaddr(iflib_get_ifp(ctx), ixgbe_mc_filter_apply, + adapter); fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); Index: sys/dev/ixl/if_iavf.c =================================================================== --- sys/dev/ixl/if_iavf.c +++ sys/dev/ixl/if_iavf.c @@ -1225,18 +1225,13 @@ iavf_enable_adminq_irq(hw); } -static int -iavf_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int count __unused) +static u_int +iavf_mc_filter_apply(void *arg, struct sockaddr_dl *sdl, u_int count) { struct iavf_sc *sc = arg; - int error = 0; - - if (ifma->ifma_addr->sa_family != AF_LINK) - return (0); - error = iavf_add_mac_filter(sc, - (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr), - IXL_FILTER_MC); + int error; + error = iavf_add_mac_filter(sc, (u8*)LLADDR(sdl), IXL_FILTER_MC); return (!error); } @@ -1244,12 +1239,11 @@ iavf_if_multi_set(if_ctx_t ctx) { struct iavf_sc *sc = iflib_get_softc(ctx); - int mcnt = 0; IOCTL_DEBUGOUT("iavf_if_multi_set: begin"); - mcnt = if_multiaddr_count(iflib_get_ifp(ctx), MAX_MULTICAST_ADDR); - if (__predict_false(mcnt == MAX_MULTICAST_ADDR)) { + if (__predict_false(if_llmaddr_count(iflib_get_ifp(ctx)) >= + MAX_MULTICAST_ADDR)) { /* Delete MC filters and enable mulitcast promisc instead */ iavf_init_multi(sc); sc->promisc_flags |= FLAG_VF_MULTICAST_PROMISC; @@ -1261,9 +1255,8 @@ iavf_init_multi(sc); /* And (re-)install filters for all mcast addresses */ - mcnt = if_multi_apply(iflib_get_ifp(ctx), iavf_mc_filter_apply, sc); - - if (mcnt > 0) + if (if_foreach_llmaddr(iflib_get_ifp(ctx), iavf_mc_filter_apply, sc) > + 0) iavf_send_vc_msg(sc, IAVF_FLAG_AQ_ADD_MAC_FILTER); } @@ -1358,8 +1351,8 @@ sc->promisc_flags = 0; - if (flags & IFF_ALLMULTI || - if_multiaddr_count(ifp, MAX_MULTICAST_ADDR) == MAX_MULTICAST_ADDR) + if (flags & IFF_ALLMULTI || if_llmaddr_count(ifp) >= + MAX_MULTICAST_ADDR) sc->promisc_flags |= FLAG_VF_MULTICAST_PROMISC; if (flags & IFF_PROMISC) sc->promisc_flags |= FLAG_VF_UNICAST_PROMISC; Index: sys/dev/ixl/if_ixl.c =================================================================== --- sys/dev/ixl/if_ixl.c +++ sys/dev/ixl/if_ixl.c @@ -122,7 +122,7 @@ #endif /*** Other ***/ -static int ixl_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int); +static u_int ixl_mc_filter_apply(void *, struct sockaddr_dl *, u_int); static void ixl_save_pf_tunables(struct ixl_pf *); static int ixl_allocate_pci_resources(struct ixl_pf *); @@ -1298,12 +1298,12 @@ struct ixl_pf *pf = iflib_get_softc(ctx); struct ixl_vsi *vsi = &pf->vsi; struct i40e_hw *hw = vsi->hw; - int mcnt = 0, flags; + int mcnt, flags; int del_mcnt; IOCTL_DEBUGOUT("ixl_if_multi_set: begin"); - mcnt = if_multiaddr_count(iflib_get_ifp(ctx), MAX_MULTICAST_ADDR); + mcnt = min(if_llmaddr_count(iflib_get_ifp(ctx)), MAX_MULTICAST_ADDR); /* Delete filters for removed multicast addresses */ del_mcnt = ixl_del_multi(vsi); vsi->num_macs -= del_mcnt; @@ -1315,8 +1315,7 @@ } /* (re-)install filters for all mcast addresses */ /* XXX: This bypasses filter count tracking code! */ - mcnt = if_multi_apply(iflib_get_ifp(ctx), ixl_mc_filter_apply, vsi); - + mcnt = if_foreach_llmaddr(iflib_get_ifp(ctx), ixl_mc_filter_apply, vsi); if (mcnt > 0) { vsi->num_macs += mcnt; flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); @@ -1504,8 +1503,8 @@ if (flags & IFF_PROMISC) uni = multi = TRUE; - else if (flags & IFF_ALLMULTI || - if_multiaddr_count(ifp, MAX_MULTICAST_ADDR) == MAX_MULTICAST_ADDR) + else if (flags & IFF_ALLMULTI || if_llmaddr_count(ifp) >= + MAX_MULTICAST_ADDR) multi = TRUE; err = i40e_aq_set_vsi_unicast_promiscuous(hw, @@ -1634,15 +1633,12 @@ return (error); } -static int -ixl_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int count __unused) +static u_int +ixl_mc_filter_apply(void *arg, struct sockaddr_dl *sdl, u_int count) { struct ixl_vsi *vsi = arg; - if (ifma->ifma_addr->sa_family != AF_LINK) - return (0); - ixl_add_mc_filter(vsi, - (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); + ixl_add_mc_filter(vsi, (u8*)LLADDR(sdl)); return (1); } Index: sys/dev/ixl/ixl_pf_main.c =================================================================== --- sys/dev/ixl/ixl_pf_main.c +++ sys/dev/ixl/ixl_pf_main.c @@ -637,6 +637,16 @@ return (FILTER_HANDLED); } +static u_int +ixl_add_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct ixl_vsi *vsi = arg; + + ixl_add_mc_filter(vsi, (u8*)LLADDR(sdl)); + + return (1); +} + /********************************************************************* * Filter Routines * @@ -646,25 +656,17 @@ void ixl_add_multi(struct ixl_vsi *vsi) { - struct ifmultiaddr *ifma; struct ifnet *ifp = vsi->ifp; struct i40e_hw *hw = vsi->hw; int mcnt = 0, flags; IOCTL_DEBUGOUT("ixl_add_multi: begin"); - if_maddr_rlock(ifp); /* ** First just get a count, to decide if we ** we simply use multicast promiscuous. */ - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - mcnt++; - } - if_maddr_runlock(ifp); - + mcnt = if_llmaddr_count(ifp); if (__predict_false(mcnt >= MAX_MULTICAST_ADDR)) { /* delete existing MC filters */ ixl_del_hw_filters(vsi, mcnt); @@ -673,16 +675,7 @@ return; } - mcnt = 0; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - ixl_add_mc_filter(vsi, - (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); - mcnt++; - } - if_maddr_runlock(ifp); + mcnt = if_foreach_llmaddr(ifp, ixl_add_maddr, vsi); if (mcnt > 0) { flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); ixl_add_hw_filters(vsi, flags, mcnt); @@ -691,38 +684,33 @@ IOCTL_DEBUGOUT("ixl_add_multi: end"); } +static u_int +ixl_match_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct ixl_mac_filter *f = arg; + + if (cmp_etheraddr(f->macaddr, (u8 *)LLADDR(sdl))) + return (1); + else + return (0); +} + int ixl_del_multi(struct ixl_vsi *vsi) { struct ifnet *ifp = vsi->ifp; - struct ifmultiaddr *ifma; struct ixl_mac_filter *f; int mcnt = 0; - bool match = FALSE; IOCTL_DEBUGOUT("ixl_del_multi: begin"); - /* Search for removed multicast addresses */ - if_maddr_rlock(ifp); - SLIST_FOREACH(f, &vsi->ftl, next) { - if ((f->flags & IXL_FILTER_USED) && (f->flags & IXL_FILTER_MC)) { - match = FALSE; - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - u8 *mc_addr = (u8 *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); - if (cmp_etheraddr(f->macaddr, mc_addr)) { - match = TRUE; - break; - } - } - if (match == FALSE) { - f->flags |= IXL_FILTER_DEL; - mcnt++; - } + SLIST_FOREACH(f, &vsi->ftl, next) + if ((f->flags & IXL_FILTER_USED) && + (f->flags & IXL_FILTER_MC) && + (if_foreach_llmaddr(ifp, ixl_match_maddr, f) == 0)) { + f->flags |= IXL_FILTER_DEL; + mcnt++; } - } - if_maddr_runlock(ifp); if (mcnt > 0) ixl_del_hw_filters(vsi, mcnt); Index: sys/dev/jme/if_jme.c =================================================================== --- sys/dev/jme/if_jme.c +++ sys/dev/jme/if_jme.c @@ -3236,12 +3236,26 @@ CSR_WRITE_4(sc, JME_RXMAC, reg); } +static u_int +jme_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t crc, *mchash = arg; + + crc = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); + + /* Just want the 6 least significant bits. */ + crc &= 0x3f; + + /* Set the corresponding bit in the hash table. */ + mchash[crc >> 5] |= 1 << (crc & 0x1f); + + return (1); +} + static void jme_set_filter(struct jme_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t crc; uint32_t mchash[2]; uint32_t rxcfg; @@ -3276,21 +3290,7 @@ */ rxcfg |= RXMAC_MULTICAST; bzero(mchash, sizeof(mchash)); - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &sc->jme_ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - - /* Just want the 6 least significant bits. */ - crc &= 0x3f; - - /* Set the corresponding bit in the hash table. */ - mchash[crc >> 5] |= 1 << (crc & 0x1f); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, jme_hash_maddr, &mchash); CSR_WRITE_4(sc, JME_MAR0, mchash[0]); CSR_WRITE_4(sc, JME_MAR1, mchash[1]); Index: sys/dev/le/lance.c =================================================================== --- sys/dev/le/lance.c +++ sys/dev/le/lance.c @@ -577,6 +577,27 @@ return (error); } +struct lance_hash_maddr_ctx { + struct lance_softc *sc; + uint16_t *af; +}; + +static u_int +lance_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct lance_hash_maddr_ctx *ctx = arg; + struct lance_softc *sc = ctx->sc; + uint32_t crc; + + crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN); + /* Just want the 6 most significant bits. */ + crc >>= 26; + /* Set the corresponding bit in the filter. */ + ctx->af[crc >> 4] |= LE_HTOLE16(1 << (crc & 0xf)); + + return (1); +} + /* * Set up the logical address filter. */ @@ -584,8 +605,7 @@ lance_setladrf(struct lance_softc *sc, uint16_t *af) { struct ifnet *ifp = sc->sc_ifp; - struct ifmultiaddr *ifma; - uint32_t crc; + struct lance_hash_maddr_ctx ctx = { sc, af }; /* * Set up multicast address filter by passing all multicast addresses @@ -601,21 +621,7 @@ } af[0] = af[1] = af[2] = af[3] = 0x0000; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - crc = ether_crc32_le(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - - /* Just want the 6 most significant bits. */ - crc >>= 26; - - /* Set the corresponding bit in the filter. */ - af[crc >> 4] |= LE_HTOLE16(1 << (crc & 0xf)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, lance_hash_maddr, &ctx); } /* Index: sys/dev/lge/if_lge.c =================================================================== --- sys/dev/lge/if_lge.c +++ sys/dev/lge/if_lge.c @@ -367,13 +367,25 @@ return; } +static u_int +lge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int count) +{ + uint32_t h, *hashes = arg; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + return (1); +} + static void lge_setmulti(sc) struct lge_softc *sc; { struct ifnet *ifp; - struct ifmultiaddr *ifma; - u_int32_t h = 0, hashes[2] = { 0, 0 }; + uint32_t hashes[2] = { 0, 0 }; ifp = sc->lge_ifp; LGE_LOCK_ASSERT(sc); @@ -392,18 +404,7 @@ CSR_WRITE_4(sc, LGE_MAR1, 0); /* now program new ones */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, lge_hash_maddr, hashes); CSR_WRITE_4(sc, LGE_MAR0, hashes[0]); CSR_WRITE_4(sc, LGE_MAR1, hashes[1]); Index: sys/dev/liquidio/lio_ioctl.c =================================================================== --- sys/dev/liquidio/lio_ioctl.c +++ sys/dev/liquidio/lio_ioctl.c @@ -491,6 +491,22 @@ return (f); } +static u_int +lio_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint64_t *mc = arg; + + if (cnt == LIO_MAX_MULTICAST_ADDR) + return (0); + + mc += cnt; + *mc = 0; + memcpy(((uint8_t *)mc) + 2, LLADDR(sdl), ETHER_ADDR_LEN); + /* no need to swap bytes */ + + return (1); +} + /* @param ifp network device */ static int lio_set_mcast_list(struct ifnet *ifp) @@ -498,9 +514,7 @@ struct lio *lio = if_getsoftc(ifp); struct octeon_device *oct = lio->oct_dev; struct lio_ctrl_pkt nctrl; - struct ifmultiaddr *ifma; - uint64_t *mc; - int mc_count = 0; + int mc_count; int ret; bzero(&nctrl, sizeof(struct lio_ctrl_pkt)); @@ -514,26 +528,7 @@ nctrl.cb_fn = lio_ctrl_cmd_completion; /* copy all the addresses into the udd */ - mc = &nctrl.udd[0]; - - /* to protect access to if_multiaddrs */ - if_maddr_rlock(ifp); - - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - *mc = 0; - memcpy(((uint8_t *)mc) + 2, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - ETHER_ADDR_LEN); - /* no need to swap bytes */ - - mc_count++; - if (++mc > &nctrl.udd[LIO_MAX_MULTICAST_ADDR]) - break; - } - - if_maddr_runlock(ifp); + mc_count = if_foreach_llmaddr(ifp, lio_copy_maddr, &nctrl.udd[0]); /* * Apparently, any activity in this call from the kernel has to Index: sys/dev/malo/if_malo.c =================================================================== --- sys/dev/malo/if_malo.c +++ sys/dev/malo/if_malo.c @@ -1510,49 +1510,46 @@ ieee80211_start_all(ic); /* start all vap's */ } +struct malo_copy_maddr_ctx { + uint8_t macs[IEEE80211_ADDR_LEN * MALO_HAL_MCAST_MAX]; + int nmc; +}; + +static u_int +malo_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int nmc) +{ + struct malo_copy_maddr_ctx *ctx = arg; + + if (ctx->nmc == MALO_HAL_MCAST_MAX) + return (0); + + IEEE80211_ADDR_COPY(ctx->macs + (ctx->nmc * IEEE80211_ADDR_LEN), + LLADDR(sdl)); + ctx->nmc++; + + return (1); +} + /* * Set the multicast filter contents into the hardware. */ static void malo_setmcastfilter(struct malo_softc *sc) { + struct malo_copy_maddr_ctx ctx; struct ieee80211com *ic = &sc->malo_ic; struct ieee80211vap *vap; - uint8_t macs[IEEE80211_ADDR_LEN * MALO_HAL_MCAST_MAX]; - uint8_t *mp; - int nmc; - mp = macs; - nmc = 0; if (ic->ic_opmode == IEEE80211_M_MONITOR || ic->ic_allmulti > 0 || ic->ic_promisc > 0) goto all; - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - struct ifnet *ifp; - struct ifmultiaddr *ifma; - - ifp = vap->iv_ifp; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - if (nmc == MALO_HAL_MCAST_MAX) { - ifp->if_flags |= IFF_ALLMULTI; - if_maddr_runlock(ifp); - goto all; - } - IEEE80211_ADDR_COPY(mp, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - - mp += IEEE80211_ADDR_LEN, nmc++; - } - if_maddr_runlock(ifp); - } + ctx.nmc = 0; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if_foreach_llmaddr(vap->iv_ifp, malo_copy_maddr, &ctx); - malo_hal_setmcast(sc->malo_mh, nmc, macs); + malo_hal_setmcast(sc->malo_mh, ctx.nmc, ctx.macs); all: /* Index: sys/dev/mge/if_mge.c =================================================================== --- sys/dev/mge/if_mge.c +++ sys/dev/mge/if_mge.c @@ -2032,45 +2032,51 @@ return(crc); } +struct mge_hash_maddr_ctx { + uint32_t smt[MGE_MCAST_REG_NUMBER]; + uint32_t omt[MGE_MCAST_REG_NUMBER]; +}; + +static u_int +mge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + static const uint8_t special[5] = { 0x01, 0x00, 0x5E, 0x00, 0x00 }; + struct mge_hash_maddr_ctx *ctx = arg; + static const uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1; + uint8_t *mac; + int i; + + mac = LLADDR(sdl); + if (memcmp(mac, special, sizeof(special)) == 0) { + i = mac[5]; + ctx->smt[i >> 2] |= v << ((i & 0x03) << 3); + } else { + i = mge_crc8(mac, ETHER_ADDR_LEN); + ctx->omt[i >> 2] |= v << ((i & 0x03) << 3); + } + return (1); +} + static void mge_setup_multicast(struct mge_softc *sc) { - uint8_t special[5] = { 0x01, 0x00, 0x5E, 0x00, 0x00 }; - uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1; - uint32_t smt[MGE_MCAST_REG_NUMBER]; - uint32_t omt[MGE_MCAST_REG_NUMBER]; + struct mge_hash_maddr_ctx ctx; struct ifnet *ifp = sc->ifp; - struct ifmultiaddr *ifma; - uint8_t *mac; + static const uint8_t v = (MGE_RX_DEFAULT_QUEUE << 1) | 1; int i; if (ifp->if_flags & IFF_ALLMULTI) { for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) - smt[i] = omt[i] = (v << 24) | (v << 16) | (v << 8) | v; + ctx.smt[i] = ctx.omt[i] = + (v << 24) | (v << 16) | (v << 8) | v; } else { - memset(smt, 0, sizeof(smt)); - memset(omt, 0, sizeof(omt)); - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - mac = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); - if (memcmp(mac, special, sizeof(special)) == 0) { - i = mac[5]; - smt[i >> 2] |= v << ((i & 0x03) << 3); - } else { - i = mge_crc8(mac, ETHER_ADDR_LEN); - omt[i >> 2] |= v << ((i & 0x03) << 3); - } - } - if_maddr_runlock(ifp); + memset(&ctx, 0, sizeof(ctx)); + if_foreach_llmaddr(ifp, mge_hash_maddr, &ctx); } for (i = 0; i < MGE_MCAST_REG_NUMBER; i++) { - MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), smt[i]); - MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), omt[i]); + MGE_WRITE(sc, MGE_DA_FILTER_SPEC_MCAST(i), ctx.smt[i]); + MGE_WRITE(sc, MGE_DA_FILTER_OTH_MCAST(i), ctx.omt[i]); } } Index: sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c =================================================================== --- sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c +++ sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c @@ -617,31 +617,30 @@ } } +static u_int mlx4_copy_addr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct mlx4_en_priv *priv = arg; + struct mlx4_en_addr_list *tmp; + + if (sdl->sdl_alen != ETHER_ADDR_LEN) /* XXXGL: can that happen? */ + return (0); + tmp = kzalloc(sizeof(struct mlx4_en_addr_list), GFP_ATOMIC); + if (tmp == NULL) { + en_err(priv, "Failed to allocate address list\n"); + return (0); + } + memcpy(tmp->addr, LLADDR(sdl), ETH_ALEN); + list_add_tail(&tmp->list, &priv->uc_list); + + return (1); +} + static void mlx4_en_cache_uclist(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_addr_list *tmp; - struct ifaddr *ifa; mlx4_en_clear_uclist(dev); - - if_addr_rlock(dev); - CK_STAILQ_FOREACH(ifa, &dev->if_addrhead, ifa_link) { - if (ifa->ifa_addr->sa_family != AF_LINK) - continue; - if (((struct sockaddr_dl *)ifa->ifa_addr)->sdl_alen != - ETHER_ADDR_LEN) - continue; - tmp = kzalloc(sizeof(struct mlx4_en_addr_list), GFP_ATOMIC); - if (tmp == NULL) { - en_err(priv, "Failed to allocate address list\n"); - break; - } - memcpy(tmp->addr, - LLADDR((struct sockaddr_dl *)ifa->ifa_addr), ETH_ALEN); - list_add_tail(&tmp->list, &priv->uc_list); - } - if_addr_runlock(dev); + if_foreach_lladdr(dev, mlx4_copy_addr, priv); } static void mlx4_en_clear_mclist(struct net_device *dev) @@ -655,31 +654,29 @@ } } +static u_int mlx4_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int count) +{ + struct mlx4_en_priv *priv = arg; + struct mlx4_en_addr_list *tmp; + + if (sdl->sdl_alen != ETHER_ADDR_LEN) /* XXXGL: can that happen? */ + return (0); + tmp = kzalloc(sizeof(struct mlx4_en_addr_list), GFP_ATOMIC); + if (tmp == NULL) { + en_err(priv, "Failed to allocate address list\n"); + return (0); + } + memcpy(tmp->addr, LLADDR(sdl), ETH_ALEN); + list_add_tail(&tmp->list, &priv->mc_list); + return (1); +} + static void mlx4_en_cache_mclist(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); - struct mlx4_en_addr_list *tmp; - struct ifmultiaddr *ifma; mlx4_en_clear_mclist(dev); - - if_maddr_rlock(dev); - CK_STAILQ_FOREACH(ifma, &dev->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (((struct sockaddr_dl *)ifma->ifma_addr)->sdl_alen != - ETHER_ADDR_LEN) - continue; - tmp = kzalloc(sizeof(struct mlx4_en_addr_list), GFP_ATOMIC); - if (tmp == NULL) { - en_err(priv, "Failed to allocate address list\n"); - break; - } - memcpy(tmp->addr, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr), ETH_ALEN); - list_add_tail(&tmp->list, &priv->mc_list); - } - if_maddr_runlock(dev); + if_foreach_llmaddr(dev, mlx4_copy_maddr, priv); } static void update_addr_list_flags(struct mlx4_en_priv *priv, Index: sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c =================================================================== --- sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c +++ sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c @@ -787,43 +787,47 @@ return (hn); } +struct mlx5e_copy_addr_ctx { + struct mlx5e_eth_addr_hash_head *free; + struct mlx5e_eth_addr_hash_head *fill; + bool success; +}; + +static u_int +mlx5e_copy_addr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct mlx5e_copy_addr_ctx *ctx = arg; + struct mlx5e_eth_addr_hash_node *hn; + + hn = mlx5e_move_hn(ctx->free, ctx->fill); + if (hn == NULL) { + ctx->success = false; + return (0); + } + ether_addr_copy(hn->ai.addr, LLADDR(sdl)); + + return (1); +} + static void mlx5e_sync_ifp_addr(struct mlx5e_priv *priv) { + struct mlx5e_copy_addr_ctx ctx; struct mlx5e_eth_addr_hash_head head_free; struct mlx5e_eth_addr_hash_head head_uc; struct mlx5e_eth_addr_hash_head head_mc; struct mlx5e_eth_addr_hash_node *hn; struct ifnet *ifp = priv->ifp; - struct ifaddr *ifa; - struct ifmultiaddr *ifma; - bool success = false; size_t x; size_t num; PRIV_ASSERT_LOCKED(priv); +retry: LIST_INIT(&head_free); LIST_INIT(&head_uc); LIST_INIT(&head_mc); -retry: - num = 1; - - if_addr_rlock(ifp); - CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - if (ifa->ifa_addr->sa_family != AF_LINK) - continue; - num++; - } - if_addr_runlock(ifp); - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - num++; - } - if_maddr_runlock(ifp); + num = 1 + if_lladdr_count(ifp) + if_llmaddr_count(ifp); /* allocate place holders */ for (x = 0; x != num; x++) { @@ -834,38 +838,21 @@ } hn = mlx5e_move_hn(&head_free, &head_uc); - if (hn == NULL) - goto cleanup; + MPASS(hn != NULL); ether_addr_copy(hn->ai.addr, LLADDR((struct sockaddr_dl *)(ifp->if_addr->ifa_addr))); - if_addr_rlock(ifp); - CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - if (ifa->ifa_addr->sa_family != AF_LINK) - continue; - hn = mlx5e_move_hn(&head_free, &head_uc); - if (hn == NULL) - break; - ether_addr_copy(hn->ai.addr, - LLADDR((struct sockaddr_dl *)ifa->ifa_addr)); - } - if_addr_runlock(ifp); - if (ifa != NULL) + ctx.free = &head_free; + ctx.fill = &head_uc; + ctx.success = true; + if_foreach_lladdr(ifp, mlx5e_copy_addr, &ctx); + if (ctx.success == false) goto cleanup; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - hn = mlx5e_move_hn(&head_free, &head_mc); - if (hn == NULL) - break; - ether_addr_copy(hn->ai.addr, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - } - if_maddr_runlock(ifp); - if (ifma != NULL) + ctx.fill = &head_mc; + if_foreach_llmaddr(ifp, mlx5e_copy_addr, &ctx); + if (ctx.success == false) goto cleanup; /* insert L2 unicast addresses into hash list */ @@ -884,8 +871,6 @@ continue; } - success = true; - cleanup: while ((hn = mlx5e_remove_hn(&head_uc)) != NULL) free(hn, M_MLX5EN); @@ -894,7 +879,7 @@ while ((hn = mlx5e_remove_hn(&head_free)) != NULL) free(hn, M_MLX5EN); - if (success == false) + if (ctx.success == false) goto retry; } Index: sys/dev/msk/if_msk.c =================================================================== --- sys/dev/msk/if_msk.c +++ sys/dev/msk/if_msk.c @@ -573,14 +573,27 @@ } } +static u_int +msk_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *mchash = arg; + uint32_t crc; + + crc = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); + /* Just want the 6 least significant bits. */ + crc &= 0x3f; + /* Set the corresponding bit in the hash table. */ + mchash[crc >> 5] |= 1 << (crc & 0x1f); + + return (1); +} + static void msk_rxfilter(struct msk_if_softc *sc_if) { struct msk_softc *sc; struct ifnet *ifp; - struct ifmultiaddr *ifma; uint32_t mchash[2]; - uint32_t crc; uint16_t mode; sc = sc_if->msk_softc; @@ -599,18 +612,7 @@ mchash[1] = 0xffff; } else { mode |= GM_RXCR_UCF_ENA; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - /* Just want the 6 least significant bits. */ - crc &= 0x3f; - /* Set the corresponding bit in the hash table. */ - mchash[crc >> 5] |= 1 << (crc & 0x1f); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, msk_hash_maddr, mchash); if (mchash[0] != 0 || mchash[1] != 0) mode |= GM_RXCR_MCF_ENA; } Index: sys/dev/mxge/if_mxge.c =================================================================== --- sys/dev/mxge/if_mxge.c +++ sys/dev/mxge/if_mxge.c @@ -1091,12 +1091,35 @@ } } +struct mxge_add_maddr_ctx { + mxge_softc_t *sc; + int error; +}; + +static u_int +mxge_add_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct mxge_add_maddr_ctx *ctx = arg; + mxge_cmd_t cmd; + + if (ctx->error != 0) + return (0); + bcopy(LLADDR(sdl), &cmd.data0, 4); + bcopy(LLADDR(sdl) + 4, &cmd.data1, 2); + cmd.data0 = htonl(cmd.data0); + cmd.data1 = htonl(cmd.data1); + + ctx->error = mxge_send_cmd(ctx->sc, MXGEFW_JOIN_MULTICAST_GROUP, &cmd); + + return (1); +} + static void mxge_set_multicast_list(mxge_softc_t *sc) { - mxge_cmd_t cmd; - struct ifmultiaddr *ifma; + struct mxge_add_maddr_ctx ctx; struct ifnet *ifp = sc->ifp; + mxge_cmd_t cmd; int err; /* This firmware is known to not support multicast */ @@ -1129,28 +1152,16 @@ } /* Walk the multicast list, and add each address */ - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - &cmd.data0, 4); - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr) + 4, - &cmd.data1, 2); - cmd.data0 = htonl(cmd.data0); - cmd.data1 = htonl(cmd.data1); - err = mxge_send_cmd(sc, MXGEFW_JOIN_MULTICAST_GROUP, &cmd); - if (err != 0) { - device_printf(sc->dev, "Failed " - "MXGEFW_JOIN_MULTICAST_GROUP, error status:" - "%d\t", err); - /* abort, leaving multicast filtering off */ - if_maddr_runlock(ifp); - return; - } + ctx.sc = sc; + ctx.error = 0; + if_foreach_llmaddr(ifp, mxge_add_maddr, &ctx); + if (ctx.error != 0) { + device_printf(sc->dev, "Failed MXGEFW_JOIN_MULTICAST_GROUP, " + "error status:" "%d\t", ctx.error); + /* abort, leaving multicast filtering off */ + return; } - if_maddr_runlock(ifp); + /* Enable multicast filtering */ err = mxge_send_cmd(sc, MXGEFW_DISABLE_ALLMULTI, &cmd); if (err != 0) { Index: sys/dev/my/if_my.c =================================================================== --- sys/dev/my/if_my.c +++ sys/dev/my/if_my.c @@ -304,7 +304,20 @@ return; } +static u_int +my_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *hashes = arg; + int h; + + h = ~ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + return (1); +} /* * Program the 64-bit multicast hash filter. */ @@ -312,11 +325,8 @@ my_setmulti(struct my_softc * sc) { struct ifnet *ifp; - int h = 0; u_int32_t hashes[2] = {0, 0}; - struct ifmultiaddr *ifma; u_int32_t rxfilt; - int mcnt = 0; MY_LOCK_ASSERT(sc); @@ -337,28 +347,13 @@ CSR_WRITE_4(sc, MY_MAR1, 0); /* now program new ones */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ~ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - mcnt++; - } - if_maddr_runlock(ifp); - - if (mcnt) + if (if_foreach_llmaddr(ifp, my_hash_maddr, hashes) > 0) rxfilt |= MY_AM; else rxfilt &= ~MY_AM; CSR_WRITE_4(sc, MY_MAR0, hashes[0]); CSR_WRITE_4(sc, MY_MAR1, hashes[1]); CSR_WRITE_4(sc, MY_TCRRCR, rxfilt); - return; } /* Index: sys/dev/nfe/if_nfe.c =================================================================== --- sys/dev/nfe/if_nfe.c +++ sys/dev/nfe/if_nfe.c @@ -2557,75 +2557,67 @@ return (0); } +struct nfe_hash_maddr_ctx { + uint8_t addr[ETHER_ADDR_LEN]; + uint8_t mask[ETHER_ADDR_LEN]; +}; + +static u_int +nfe_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct nfe_hash_maddr_ctx *ctx = arg; + uint8_t *addrp, mcaddr; + int j; + + addrp = LLADDR(sdl); + for (j = 0; j < ETHER_ADDR_LEN; j++) { + mcaddr = addrp[j]; + ctx->addr[j] &= mcaddr; + ctx->mask[j] &= ~mcaddr; + } + + return (1); +} static void nfe_setmulti(struct nfe_softc *sc) { if_t ifp = sc->nfe_ifp; - int i, mc_count, mcnt; + struct nfe_hash_maddr_ctx ctx; uint32_t filter; - uint8_t addr[ETHER_ADDR_LEN], mask[ETHER_ADDR_LEN]; uint8_t etherbroadcastaddr[ETHER_ADDR_LEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - uint8_t *mta; + int i; NFE_LOCK_ASSERT(sc); if ((if_getflags(ifp) & (IFF_ALLMULTI | IFF_PROMISC)) != 0) { - bzero(addr, ETHER_ADDR_LEN); - bzero(mask, ETHER_ADDR_LEN); - goto done; - } - - bcopy(etherbroadcastaddr, addr, ETHER_ADDR_LEN); - bcopy(etherbroadcastaddr, mask, ETHER_ADDR_LEN); - - mc_count = if_multiaddr_count(ifp, -1); - mta = malloc(sizeof(uint8_t) * ETHER_ADDR_LEN * mc_count, M_DEVBUF, - M_NOWAIT); - - /* Unable to get memory - process without filtering */ - if (mta == NULL) { - device_printf(sc->nfe_dev, "nfe_setmulti: failed to allocate" - "temp multicast buffer!\n"); - - bzero(addr, ETHER_ADDR_LEN); - bzero(mask, ETHER_ADDR_LEN); + bzero(ctx.addr, ETHER_ADDR_LEN); + bzero(ctx.mask, ETHER_ADDR_LEN); goto done; } - if_multiaddr_array(ifp, mta, &mcnt, mc_count); - - for (i = 0; i < mcnt; i++) { - uint8_t *addrp; - int j; - - addrp = mta + (i * ETHER_ADDR_LEN); - for (j = 0; j < ETHER_ADDR_LEN; j++) { - u_int8_t mcaddr = addrp[j]; - addr[j] &= mcaddr; - mask[j] &= ~mcaddr; - } - } + bcopy(etherbroadcastaddr, ctx.addr, ETHER_ADDR_LEN); + bcopy(etherbroadcastaddr, ctx.mask, ETHER_ADDR_LEN); - free(mta, M_DEVBUF); + if_foreach_llmaddr(ifp, nfe_hash_maddr, &ctx); for (i = 0; i < ETHER_ADDR_LEN; i++) { - mask[i] |= addr[i]; + ctx.mask[i] |= ctx.addr[i]; } done: - addr[0] |= 0x01; /* make sure multicast bit is set */ + ctx.addr[0] |= 0x01; /* make sure multicast bit is set */ - NFE_WRITE(sc, NFE_MULTIADDR_HI, - addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); + NFE_WRITE(sc, NFE_MULTIADDR_HI, ctx.addr[3] << 24 | ctx.addr[2] << 16 | + ctx.addr[1] << 8 | ctx.addr[0]); NFE_WRITE(sc, NFE_MULTIADDR_LO, - addr[5] << 8 | addr[4]); - NFE_WRITE(sc, NFE_MULTIMASK_HI, - mask[3] << 24 | mask[2] << 16 | mask[1] << 8 | mask[0]); + ctx.addr[5] << 8 | ctx.addr[4]); + NFE_WRITE(sc, NFE_MULTIMASK_HI, ctx.mask[3] << 24 | ctx.mask[2] << 16 | + ctx.mask[1] << 8 | ctx.mask[0]); NFE_WRITE(sc, NFE_MULTIMASK_LO, - mask[5] << 8 | mask[4]); + ctx.mask[5] << 8 | ctx.mask[4]); filter = NFE_READ(sc, NFE_RXFILTER); filter &= NFE_PFF_RX_PAUSE; Index: sys/dev/nge/if_nge.c =================================================================== --- sys/dev/nge/if_nge.c +++ sys/dev/nge/if_nge.c @@ -661,13 +661,33 @@ CSR_READ_4(sc, NGE_GPIO) & ~NGE_GPIO_GP3_OUT); } +static u_int +nge_write_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct nge_softc *sc = arg; + uint32_t h; + int bit, index; + + /* + * From the 11 bits returned by the crc routine, the top 7 + * bits represent the 16-bit word in the mcast hash table + * that needs to be updated, and the lower 4 bits represent + * which bit within that byte needs to be set. + */ + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 21; + index = (h >> 4) & 0x7F; + bit = h & 0xF; + CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_MCAST_LO + (index * 2)); + NGE_SETBIT(sc, NGE_RXFILT_DATA, (1 << bit)); + + return (1); +} + static void nge_rxfilter(struct nge_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t h, i, rxfilt; - int bit, index; + uint32_t i, rxfilt; NGE_LOCK_ASSERT(sc); ifp = sc->nge_ifp; @@ -720,26 +740,7 @@ CSR_WRITE_4(sc, NGE_RXFILT_DATA, 0); } - /* - * From the 11 bits returned by the crc routine, the top 7 - * bits represent the 16-bit word in the mcast hash table - * that needs to be updated, and the lower 4 bits represent - * which bit within that byte needs to be set. - */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 21; - index = (h >> 4) & 0x7F; - bit = h & 0xF; - CSR_WRITE_4(sc, NGE_RXFILT_CTL, - NGE_FILTADDR_MCAST_LO + (index * 2)); - NGE_SETBIT(sc, NGE_RXFILT_DATA, (1 << bit)); - } - if_maddr_runlock(ifp); - + if_foreach_llmaddr(ifp, nge_write_maddr, sc); done: CSR_WRITE_4(sc, NGE_RXFILT_CTL, rxfilt); /* Turn the receive filter on. */ Index: sys/dev/oce/oce_hw.c =================================================================== --- sys/dev/oce/oce_hw.c +++ sys/dev/oce/oce_hw.c @@ -544,6 +544,20 @@ } +static u_int +oce_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct mbx_set_common_iface_multicast *req = arg; + + if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) + return (0); + + bcopy(LLADDR(sdl), &req->params.req.mac[req->params.req.num_mac++], + ETH_ADDR_LEN); + + return (1); +} + /** * @brief Function for hardware update multicast filter @@ -553,7 +567,6 @@ oce_hw_update_multicast(POCE_SOFTC sc) { struct ifnet *ifp = sc->ifp; - struct ifmultiaddr *ifma; struct mbx_set_common_iface_multicast *req = NULL; OCE_DMA_MEM dma; int rc = 0; @@ -566,29 +579,15 @@ req = OCE_DMAPTR(&dma, struct mbx_set_common_iface_multicast); bzero(req, sizeof(struct mbx_set_common_iface_multicast)); -#if __FreeBSD_version > 800000 - if_maddr_rlock(ifp); -#endif - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) { - /*More multicast addresses than our hardware table - So Enable multicast promiscus in our hardware to - accept all multicat packets - */ - req->params.req.promiscuous = 1; - break; - } - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - &req->params.req.mac[req->params.req.num_mac], - ETH_ADDR_LEN); - req->params.req.num_mac = req->params.req.num_mac + 1; + if_foreach_llmaddr(ifp, oce_copy_maddr, req); + if (req->params.req.num_mac == OCE_MAX_MC_FILTER_SIZE) { + /*More multicast addresses than our hardware table + So Enable multicast promiscus in our hardware to + accept all multicat packets + */ + req->params.req.promiscuous = 1; } -#if __FreeBSD_version > 800000 - if_maddr_runlock(ifp); -#endif + req->params.req.if_id = sc->if_id; rc = oce_update_multicast(sc, &dma); oce_dma_free(sc, &dma); Index: sys/dev/otus/if_otus.c =================================================================== --- sys/dev/otus/if_otus.c +++ sys/dev/otus/if_otus.c @@ -2308,63 +2308,63 @@ return 0; } +static u_int +otus_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t val, *hashes = arg; + + val = le32dec(LLADDR(sdl) + 4); + /* Get address byte 5 */ + val = val & 0x0000ff00; + val = val >> 8; + + /* As per below, shift it >> 2 to get only 6 bits */ + val = val >> 2; + if (val < 32) + hashes[0] |= 1 << val; + else + hashes[1] |= 1 << (val - 32); + + return (1); +} + + int otus_set_multi(struct otus_softc *sc) { - uint32_t lo, hi; struct ieee80211com *ic = &sc->sc_ic; + uint32_t hashes[2]; int r; if (ic->ic_allmulti > 0 || ic->ic_promisc > 0 || ic->ic_opmode == IEEE80211_M_MONITOR) { - lo = 0xffffffff; - hi = 0xffffffff; + hashes[0] = 0xffffffff; + hashes[1] = 0xffffffff; } else { struct ieee80211vap *vap; - struct ifnet *ifp; - struct ifmultiaddr *ifma; - - lo = hi = 0; - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - ifp = vap->iv_ifp; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - caddr_t dl; - uint32_t val; - - dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); - val = le32dec(dl + 4); - /* Get address byte 5 */ - val = val & 0x0000ff00; - val = val >> 8; - - /* As per below, shift it >> 2 to get only 6 bits */ - val = val >> 2; - if (val < 32) - lo |= 1 << val; - else - hi |= 1 << (val - 32); - } - if_maddr_runlock(ifp); - } + + hashes[0] = hashes[1] = 0; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if_foreach_llmaddr(vap->iv_ifp, otus_hash_maddr, + hashes); } #if 0 /* XXX openbsd code */ while (enm != NULL) { bit = enm->enm_addrlo[5] >> 2; if (bit < 32) - lo |= 1 << bit; + hashes[0] |= 1 << bit; else - hi |= 1 << (bit - 32); + hashes[1] |= 1 << (bit - 32); ETHER_NEXT_MULTI(step, enm); } #endif - hi |= 1U << 31; /* Make sure the broadcast bit is set. */ + hashes[1] |= 1U << 31; /* Make sure the broadcast bit is set. */ OTUS_LOCK(sc); - otus_write(sc, AR_MAC_REG_GROUP_HASH_TBL_L, lo); - otus_write(sc, AR_MAC_REG_GROUP_HASH_TBL_H, hi); + otus_write(sc, AR_MAC_REG_GROUP_HASH_TBL_L, hashes[0]); + otus_write(sc, AR_MAC_REG_GROUP_HASH_TBL_H, hashes[1]); r = otus_write_barrier(sc); /* XXX operating mode? filter? */ OTUS_UNLOCK(sc); Index: sys/dev/qlnx/qlnxe/qlnx_os.c =================================================================== --- sys/dev/qlnx/qlnxe/qlnx_os.c +++ sys/dev/qlnx/qlnxe/qlnx_os.c @@ -2644,42 +2644,36 @@ } -#define QLNX_MCAST_ADDRS_SIZE (QLNX_MAX_NUM_MULTICAST_ADDRS * ETHER_HDR_LEN) -static int -qlnx_set_multi(qlnx_host_t *ha, uint32_t add_multi) +static u_int +qlnx_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int mcnt) { - uint8_t mta[QLNX_MCAST_ADDRS_SIZE]; - struct ifmultiaddr *ifma; - int mcnt = 0; - struct ifnet *ifp = ha->ifp; - int ret = 0; + uint8_t *mta = arg; - if (qlnx_vf_device(ha) == 0) + if (mcnt == QLNX_MAX_NUM_MULTICAST_ADDRS) return (0); - if_maddr_rlock(ifp); + bcopy(LLADDR(sdl), &mta[mcnt * ETHER_HDR_LEN], ETHER_HDR_LEN); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - if (mcnt == QLNX_MAX_NUM_MULTICAST_ADDRS) - break; + return (1); +} - bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), - &mta[mcnt * ETHER_HDR_LEN], ETHER_HDR_LEN); +static int +qlnx_set_multi(qlnx_host_t *ha, uint32_t add_multi) +{ + uint8_t mta[QLNX_MAX_NUM_MULTICAST_ADDRS * ETHER_HDR_LEN]; + struct ifnet *ifp = ha->ifp; + u_int mcnt; - mcnt++; - } + if (qlnx_vf_device(ha) == 0) + return (0); - if_maddr_runlock(ifp); + mcnt = if_foreach_llmaddr(ifp, qlnx_copy_maddr, mta); QLNX_LOCK(ha); qlnx_hw_set_multi(ha, mta, mcnt, add_multi); QLNX_UNLOCK(ha); - return (ret); + return (0); } static int Index: sys/dev/qlxgb/qla_os.c =================================================================== --- sys/dev/qlxgb/qla_os.c +++ sys/dev/qlxgb/qla_os.c @@ -763,32 +763,26 @@ QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__)); } +static u_int +qla_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int mcnt) +{ + uint8_t *mta = arg; + + if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS) + return (0); + bcopy(LLADDR(sdl), &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN); + + return (1); +} + static void qla_set_multi(qla_host_t *ha, uint32_t add_multi) { uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN]; - struct ifmultiaddr *ifma; - int mcnt = 0; struct ifnet *ifp = ha->ifp; + int mcnt; - if_maddr_rlock(ifp); - - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS) - break; - - bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), - &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN); - - mcnt++; - } - - if_maddr_runlock(ifp); - + mcnt = if_foreach_llmaddr(ifp, qla_copy_maddr, mta); qla_hw_set_multi(ha, mta, mcnt, add_multi); return; Index: sys/dev/qlxgbe/ql_os.c =================================================================== --- sys/dev/qlxgbe/ql_os.c +++ sys/dev/qlxgbe/ql_os.c @@ -977,32 +977,28 @@ QL_DPRINT2(ha, (ha->pci_dev, "%s: exit\n", __func__)); } +static u_int +qla_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int mcnt) +{ + uint8_t *mta = arg; + + if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS) + return (0); + + bcopy(LLADDR(sdl), &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN); + + return (1); +} + static int qla_set_multi(qla_host_t *ha, uint32_t add_multi) { uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN]; - struct ifmultiaddr *ifma; int mcnt = 0; struct ifnet *ifp = ha->ifp; int ret = 0; - if_maddr_rlock(ifp); - - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS) - break; - - bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), - &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN); - - mcnt++; - } - - if_maddr_runlock(ifp); + mcnt = if_foreach_llmaddr(ifp, qla_copy_maddr, mta); if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, QLA_LOCK_NO_SLEEP) != 0) Index: sys/dev/qlxge/qls_os.c =================================================================== --- sys/dev/qlxge/qls_os.c +++ sys/dev/qlxge/qls_os.c @@ -835,31 +835,27 @@ QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__)); } -static void -qls_set_multi(qla_host_t *ha, uint32_t add_multi) +static u_int +qls_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int mcnt) { - uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN]; - struct ifmultiaddr *ifma; - int mcnt = 0; - struct ifnet *ifp = ha->ifp; + uint8_t *mta = arg; - if_maddr_rlock(ifp); + if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS) + return (0); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS) - break; + bcopy(LLADDR(sdl), &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN); - bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), - &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN); + return (1); +} - mcnt++; - } +static void +qls_set_multi(qla_host_t *ha, uint32_t add_multi) +{ + uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN]; + struct ifnet *ifp = ha->ifp; + int mcnt; - if_maddr_runlock(ifp); + mcnt = if_foreach_llmaddr(ifp, qls_copy_maddr, mta); if (QLA_LOCK(ha, __func__, 1) == 0) { qls_hw_set_multi(ha, mta, mcnt, add_multi); Index: sys/dev/re/if_re.c =================================================================== --- sys/dev/re/if_re.c +++ sys/dev/re/if_re.c @@ -650,6 +650,20 @@ */ } +static u_int +re_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t h, *hashes = arg; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + + return (1); +} + /* * Set the RX configuration and 64-bit multicast hash filter. */ @@ -657,9 +671,8 @@ re_set_rxmode(struct rl_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t hashes[2] = { 0, 0 }; - uint32_t h, rxfilt; + uint32_t h, hashes[2] = { 0, 0 }; + uint32_t rxfilt; RL_LOCK_ASSERT(sc); @@ -684,18 +697,7 @@ goto done; } - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, re_hash_maddr, hashes); if (hashes[0] != 0 || hashes[1] != 0) { /* Index: sys/dev/rl/if_rl.c =================================================================== --- sys/dev/rl/if_rl.c +++ sys/dev/rl/if_rl.c @@ -509,6 +509,21 @@ */ } +static u_int +rl_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *hashes = arg; + int h; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + + return (1); +} + /* * Program the 64-bit multicast hash filter. */ @@ -516,9 +531,7 @@ rl_rxfilter(struct rl_softc *sc) { struct ifnet *ifp = sc->rl_ifp; - int h = 0; uint32_t hashes[2] = { 0, 0 }; - struct ifmultiaddr *ifma; uint32_t rxfilt; RL_LOCK_ASSERT(sc); @@ -539,18 +552,7 @@ hashes[1] = 0xFFFFFFFF; } else { /* Now program new ones. */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, rl_hash_maddr, hashes); if (hashes[0] != 0 || hashes[1] != 0) rxfilt |= RL_RXCFG_RX_MULTI; } Index: sys/dev/rtwn/if_rtwn_rx.c =================================================================== --- sys/dev/rtwn/if_rtwn_rx.c +++ sys/dev/rtwn/if_rtwn_rx.c @@ -366,6 +366,18 @@ return (pos); } +static u_int +rtwm_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *mfilt = arg; + uint8_t pos; + + pos = rtwn_get_multi_pos(LLADDR(sdl)); + mfilt[pos / 32] |= (1 << (pos % 32)); + + return (1); +} + void rtwn_set_multi(struct rtwn_softc *sc) { @@ -377,28 +389,13 @@ /* general structure was copied from ath(4). */ if (ic->ic_allmulti == 0) { struct ieee80211vap *vap; - struct ifnet *ifp; - struct ifmultiaddr *ifma; /* * Merge multicast addresses to form the hardware filter. */ mfilt[0] = mfilt[1] = 0; - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - ifp = vap->iv_ifp; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - caddr_t dl; - uint8_t pos; - - dl = LLADDR((struct sockaddr_dl *) - ifma->ifma_addr); - pos = rtwn_get_multi_pos(dl); - - mfilt[pos / 32] |= (1 << (pos % 32)); - } - if_maddr_runlock(ifp); - } + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if_foreach_llmaddr(vap->iv_ifp, rtwm_hash_maddr, mfilt); } else mfilt[0] = mfilt[1] = ~0; Index: sys/dev/sfxge/sfxge_port.c =================================================================== --- sys/dev/sfxge/sfxge_port.c +++ sys/dev/sfxge/sfxge_port.c @@ -358,36 +358,35 @@ SFXGE_PORT_UNLOCK(port); } +static u_int +sfxge_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint8_t *mcast_addr = arg; + + if (cnt == EFX_MAC_MULTICAST_LIST_MAX) + return (0); + + memcpy(mcast_addr + (cnt * EFX_MAC_ADDR_LEN), LLADDR(sdl), + EFX_MAC_ADDR_LEN); + + return (1); +} + static int sfxge_mac_multicast_list_set(struct sfxge_softc *sc) { struct ifnet *ifp = sc->ifnet; struct sfxge_port *port = &sc->port; - uint8_t *mcast_addr = port->mcast_addrs; - struct ifmultiaddr *ifma; - struct sockaddr_dl *sa; int rc = 0; mtx_assert(&port->lock, MA_OWNED); - port->mcast_count = 0; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family == AF_LINK) { - if (port->mcast_count == EFX_MAC_MULTICAST_LIST_MAX) { - device_printf(sc->dev, - "Too many multicast addresses\n"); - rc = EINVAL; - break; - } - - sa = (struct sockaddr_dl *)ifma->ifma_addr; - memcpy(mcast_addr, LLADDR(sa), EFX_MAC_ADDR_LEN); - mcast_addr += EFX_MAC_ADDR_LEN; - ++port->mcast_count; - } + port->mcast_count = if_foreach_llmaddr(ifp, sfxge_copy_maddr, + port->mcast_addrs); + if (port->mcast_count == EFX_MAC_MULTICAST_LIST_MAX) { + device_printf(sc->dev, "Too many multicast addresses\n"); + rc = EINVAL; } - if_maddr_runlock(ifp); if (rc == 0) { rc = efx_mac_multicast_list_set(sc->enp, port->mcast_addrs, @@ -485,6 +484,7 @@ sfxge_port_start(struct sfxge_softc *sc) { uint8_t mac_addr[ETHER_ADDR_LEN]; + struct epoch_tracker et; struct ifnet *ifp = sc->ifnet; struct sfxge_port *port; efx_nic_t *enp; @@ -518,10 +518,10 @@ goto fail3; /* Set the unicast address */ - if_addr_rlock(ifp); + NET_EPOCH_ENTER(et); bcopy(LLADDR((struct sockaddr_dl *)ifp->if_addr->ifa_addr), mac_addr, sizeof(mac_addr)); - if_addr_runlock(ifp); + NET_EPOCH_EXIT(et); if ((rc = efx_mac_addr_set(enp, mac_addr)) != 0) goto fail4; Index: sys/dev/sge/if_sge.c =================================================================== --- sys/dev/sge/if_sge.c +++ sys/dev/sge/if_sge.c @@ -442,12 +442,22 @@ } } +static u_int +sge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int count) +{ + uint32_t crc, *hashes = arg; + + crc = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); + hashes[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); + + return (1); +} + static void sge_rxfilter(struct sge_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t crc, hashes[2]; + uint32_t hashes[2]; uint16_t rxfilt; SGE_LOCK_ASSERT(sc); @@ -468,15 +478,7 @@ rxfilt |= AcceptMulticast; hashes[0] = hashes[1] = 0; /* Now program new ones. */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - hashes[crc >> 31] |= 1 << ((crc >> 26) & 0x1f); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, sge_hash_maddr, hashes); } CSR_WRITE_2(sc, RxMacControl, rxfilt); CSR_WRITE_4(sc, RxHashTable, hashes[0]); Index: sys/dev/sis/if_sis.c =================================================================== --- sys/dev/sis/if_sis.c +++ sys/dev/sis/if_sis.c @@ -694,13 +694,29 @@ sis_rxfilter_sis(sc); } +static u_int +sis_write_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct sis_softc *sc = arg; + uint32_t h; + int bit, index; + + h = sis_mchash(sc, LLADDR(sdl)); + index = h >> 3; + bit = h & 0x1F; + CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + index); + if (bit > 0xF) + bit -= 0x10; + SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << bit)); + + return (1); +} + static void sis_rxfilter_ns(struct sis_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t h, i, filter; - int bit, index; + uint32_t i, filter; ifp = sc->sis_ifp; filter = CSR_READ_4(sc, SIS_RXFILT_CTL); @@ -743,21 +759,7 @@ CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0); } - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = sis_mchash(sc, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - index = h >> 3; - bit = h & 0x1F; - CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + - index); - if (bit > 0xF) - bit -= 0x10; - SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << bit)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, sis_write_maddr, sc); } /* Turn the receive filter on */ @@ -765,13 +767,29 @@ CSR_READ_4(sc, SIS_RXFILT_CTL); } +struct sis_hash_maddr_ctx { + struct sis_softc *sc; + uint16_t hashes[16]; +}; + +static u_int +sis_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct sis_hash_maddr_ctx *ctx = arg; + uint32_t h; + + h = sis_mchash(ctx->sc, LLADDR(sdl)); + ctx->hashes[h >> 4] |= 1 << (h & 0xf); + + return (1); +} + static void sis_rxfilter_sis(struct sis_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t filter, h, i, n; - uint16_t hashes[16]; + struct sis_hash_maddr_ctx ctx; + uint32_t filter, i, n; ifp = sc->sis_ifp; @@ -796,31 +814,21 @@ if (ifp->if_flags & IFF_PROMISC) filter |= SIS_RXFILTCTL_ALLPHYS; for (i = 0; i < n; i++) - hashes[i] = ~0; + ctx.hashes[i] = ~0; } else { for (i = 0; i < n; i++) - hashes[i] = 0; - i = 0; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = sis_mchash(sc, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - hashes[h >> 4] |= 1 << (h & 0xf); - i++; - } - if_maddr_runlock(ifp); - if (i > n) { + ctx.hashes[i] = 0; + ctx.sc = sc; + if (if_foreach_llmaddr(ifp, sis_hash_maddr, &ctx) > n) { filter |= SIS_RXFILTCTL_ALLMULTI; for (i = 0; i < n; i++) - hashes[i] = ~0; + ctx.hashes[i] = ~0; } } for (i = 0; i < n; i++) { CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + i) << 16); - CSR_WRITE_4(sc, SIS_RXFILT_DATA, hashes[i]); + CSR_WRITE_4(sc, SIS_RXFILT_DATA, ctx.hashes[i]); } /* Turn the receive filter on */ Index: sys/dev/sk/if_sk.c =================================================================== --- sys/dev/sk/if_sk.c +++ sys/dev/sk/if_sk.c @@ -718,21 +718,49 @@ sk_rxfilter_yukon(sc_if); } +struct sk_add_maddr_genesis_ctx { + struct sk_if_softc *sc_if; + uint32_t hashes[2]; + uint32_t mode; +}; + +static u_int +sk_add_maddr_genesis(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct sk_add_maddr_genesis_ctx *ctx = arg; + int h; + + /* + * Program the first XM_RXFILT_MAX multicast groups + * into the perfect filter. + */ + if (cnt + 1 < XM_RXFILT_MAX) { + sk_setfilt(ctx->sc_if, (uint16_t *)LLADDR(sdl), cnt + 1); + ctx->mode |= XM_MODE_RX_USE_PERFECT; + return (1); + } + h = sk_xmchash((const uint8_t *)LLADDR(sdl)); + if (h < 32) + ctx->hashes[0] |= (1 << h); + else + ctx->hashes[1] |= (1 << (h - 32)); + ctx->mode |= XM_MODE_RX_USE_HASH; + + return (1); +} + static void -sk_rxfilter_genesis(sc_if) - struct sk_if_softc *sc_if; +sk_rxfilter_genesis(struct sk_if_softc *sc_if) { struct ifnet *ifp = sc_if->sk_ifp; - u_int32_t hashes[2] = { 0, 0 }, mode; - int h = 0, i; - struct ifmultiaddr *ifma; + struct sk_add_maddr_genesis_ctx ctx = { sc_if, { 0, 0 } }; + int i; u_int16_t dummy[] = { 0, 0, 0 }; - u_int16_t maddr[(ETHER_ADDR_LEN+1)/2]; SK_IF_LOCK_ASSERT(sc_if); - mode = SK_XM_READ_4(sc_if, XM_MODE); - mode &= ~(XM_MODE_RX_PROMISC | XM_MODE_RX_USE_HASH | + ctx.mode = SK_XM_READ_4(sc_if, XM_MODE); + ctx.mode &= ~(XM_MODE_RX_PROMISC | XM_MODE_RX_USE_HASH | XM_MODE_RX_USE_PERFECT); /* First, zot all the existing perfect filters. */ for (i = 1; i < XM_RXFILT_MAX; i++) @@ -741,53 +769,39 @@ /* Now program new ones. */ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { if (ifp->if_flags & IFF_ALLMULTI) - mode |= XM_MODE_RX_USE_HASH; + ctx.mode |= XM_MODE_RX_USE_HASH; if (ifp->if_flags & IFF_PROMISC) - mode |= XM_MODE_RX_PROMISC; - hashes[0] = 0xFFFFFFFF; - hashes[1] = 0xFFFFFFFF; - } else { - i = 1; - if_maddr_rlock(ifp); + ctx.mode |= XM_MODE_RX_PROMISC; + ctx.hashes[0] = 0xFFFFFFFF; + ctx.hashes[1] = 0xFFFFFFFF; + } else /* XXX want to maintain reverse semantics */ - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, - ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - /* - * Program the first XM_RXFILT_MAX multicast groups - * into the perfect filter. - */ - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - maddr, ETHER_ADDR_LEN); - if (i < XM_RXFILT_MAX) { - sk_setfilt(sc_if, maddr, i); - mode |= XM_MODE_RX_USE_PERFECT; - i++; - continue; - } - h = sk_xmchash((const uint8_t *)maddr); - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - mode |= XM_MODE_RX_USE_HASH; - } - if_maddr_runlock(ifp); - } + if_foreach_llmaddr(ifp, sk_add_maddr_genesis, &ctx); - SK_XM_WRITE_4(sc_if, XM_MODE, mode); - SK_XM_WRITE_4(sc_if, XM_MAR0, hashes[0]); - SK_XM_WRITE_4(sc_if, XM_MAR2, hashes[1]); + SK_XM_WRITE_4(sc_if, XM_MODE, ctx.mode); + SK_XM_WRITE_4(sc_if, XM_MAR0, ctx.hashes[0]); + SK_XM_WRITE_4(sc_if, XM_MAR2, ctx.hashes[1]); +} + +static u_int +sk_hash_maddr_yukon(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t crc, *hashes = arg; + + crc = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); + /* Just want the 6 least significant bits. */ + crc &= 0x3f; + /* Set the corresponding bit in the hash table. */ + hashes[crc >> 5] |= 1 << (crc & 0x1f); + + return (1); } static void -sk_rxfilter_yukon(sc_if) - struct sk_if_softc *sc_if; +sk_rxfilter_yukon(struct sk_if_softc *sc_if) { struct ifnet *ifp; - u_int32_t crc, hashes[2] = { 0, 0 }, mode; - struct ifmultiaddr *ifma; + uint32_t hashes[2] = { 0, 0 }, mode; SK_IF_LOCK_ASSERT(sc_if); @@ -801,18 +815,7 @@ hashes[1] = 0xFFFFFFFF; } else { mode |= YU_RCR_UFLEN; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - /* Just want the 6 least significant bits. */ - crc &= 0x3f; - /* Set the corresponding bit in the hash table. */ - hashes[crc >> 5] |= 1 << (crc & 0x1f); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, sk_hash_maddr_yukon, hashes); if (hashes[0] != 0 || hashes[1] != 0) mode |= YU_RCR_MUFLEN; } Index: sys/dev/ste/if_ste.c =================================================================== --- sys/dev/ste/if_ste.c +++ sys/dev/ste/if_ste.c @@ -405,14 +405,27 @@ return (err ? 1 : 0); } +static u_int +ste_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *hashes = arg; + int h; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) & 0x3F; + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + + return (1); +} + static void ste_rxfilter(struct ste_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; uint32_t hashes[2] = { 0, 0 }; uint8_t rxcfg; - int h; STE_LOCK_ASSERT(sc); @@ -433,18 +446,7 @@ rxcfg |= STE_RXMODE_MULTIHASH; /* Now program new ones. */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) & 0x3F; - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, ste_hash_maddr, hashes); chipit: CSR_WRITE_2(sc, STE_MAR0, hashes[0] & 0xFFFF); Index: sys/dev/stge/if_stge.c =================================================================== --- sys/dev/stge/if_stge.c +++ sys/dev/stge/if_stge.c @@ -2507,12 +2507,24 @@ CSR_WRITE_2(sc, STGE_ReceiveMode, mode); } +static u_int +stge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t crc, *mchash = arg; + + crc = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); + /* Just want the 6 least significant bits. */ + crc &= 0x3f; + /* Set the corresponding bit in the hash table. */ + mchash[crc >> 5] |= 1 << (crc & 0x1f); + + return (1); +} + static void stge_set_multi(struct stge_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t crc; uint32_t mchash[2]; uint16_t mode; int count; @@ -2542,25 +2554,8 @@ * high order bits select the register, while the rest of the bits * select the bit within the register. */ - bzero(mchash, sizeof(mchash)); - - count = 0; - if_maddr_rlock(sc->sc_ifp); - CK_STAILQ_FOREACH(ifma, &sc->sc_ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - - /* Just want the 6 least significant bits. */ - crc &= 0x3f; - - /* Set the corresponding bit in the hash table. */ - mchash[crc >> 5] |= 1 << (crc & 0x1f); - count++; - } - if_maddr_runlock(ifp); + count = if_foreach_llmaddr(ifp, stge_hash_maddr, mchash); mode &= ~(RM_ReceiveMulticast | RM_ReceiveAllFrames); if (count > 0) Index: sys/dev/ti/if_ti.c =================================================================== --- sys/dev/ti/if_ti.c +++ sys/dev/ti/if_ti.c @@ -207,8 +207,8 @@ static uint8_t ti_eeprom_getbyte(struct ti_softc *, int, uint8_t *); static int ti_read_eeprom(struct ti_softc *, caddr_t, int, int); -static void ti_add_mcast(struct ti_softc *, struct ether_addr *); -static void ti_del_mcast(struct ti_softc *, struct ether_addr *); +static u_int ti_add_mcast(void *, struct sockaddr_dl *, u_int); +static u_int ti_del_mcast(void *, struct sockaddr_dl *, u_int); static void ti_setmulti(struct ti_softc *); static void ti_mem_read(struct ti_softc *, uint32_t, uint32_t, void *); @@ -1878,14 +1878,15 @@ * but we have to support the old way too so that Tigon 1 cards will * work. */ -static void -ti_add_mcast(struct ti_softc *sc, struct ether_addr *addr) +static u_int +ti_add_mcast(void *arg, struct sockaddr_dl *sdl, u_int count) { + struct ti_softc *sc = arg; struct ti_cmd_desc cmd; uint16_t *m; uint32_t ext[2] = {0, 0}; - m = (uint16_t *)&addr->octet[0]; + m = (uint16_t *)LLADDR(sdl); switch (sc->ti_hwrev) { case TI_HWREV_TIGON: @@ -1900,18 +1901,20 @@ break; default: device_printf(sc->ti_dev, "unknown hwrev\n"); - break; + return (0); } + return (1); } -static void -ti_del_mcast(struct ti_softc *sc, struct ether_addr *addr) +static u_int +ti_del_mcast(void *arg, struct sockaddr_dl *sdl, u_int count) { + struct ti_softc *sc = arg; struct ti_cmd_desc cmd; uint16_t *m; uint32_t ext[2] = {0, 0}; - m = (uint16_t *)&addr->octet[0]; + m = (uint16_t *)LLADDR(sdl); switch (sc->ti_hwrev) { case TI_HWREV_TIGON: @@ -1926,8 +1929,10 @@ break; default: device_printf(sc->ti_dev, "unknown hwrev\n"); - break; + return (0); } + + return (1); } /* @@ -1948,9 +1953,7 @@ ti_setmulti(struct ti_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; struct ti_cmd_desc cmd; - struct ti_mc_entry *mc; uint32_t intrs; TI_LOCK_ASSERT(sc); @@ -1969,30 +1972,10 @@ CSR_WRITE_4(sc, TI_MB_HOSTINTR, 1); /* First, zot all the existing filters. */ - while (SLIST_FIRST(&sc->ti_mc_listhead) != NULL) { - mc = SLIST_FIRST(&sc->ti_mc_listhead); - ti_del_mcast(sc, &mc->mc_addr); - SLIST_REMOVE_HEAD(&sc->ti_mc_listhead, mc_entries); - free(mc, M_DEVBUF); - } + if_foreach_llmaddr(ifp, ti_del_mcast, sc); /* Now program new ones. */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - mc = malloc(sizeof(struct ti_mc_entry), M_DEVBUF, M_NOWAIT); - if (mc == NULL) { - device_printf(sc->ti_dev, - "no memory for mcast filter entry\n"); - continue; - } - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - (char *)&mc->mc_addr, ETHER_ADDR_LEN); - SLIST_INSERT_HEAD(&sc->ti_mc_listhead, mc, mc_entries); - ti_add_mcast(sc, &mc->mc_addr); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, ti_add_mcast, sc); /* Re-enable interrupts. */ CSR_WRITE_4(sc, TI_MB_HOSTINTR, intrs); Index: sys/dev/ti/if_tireg.h =================================================================== --- sys/dev/ti/if_tireg.h +++ sys/dev/ti/if_tireg.h @@ -1010,11 +1010,6 @@ #define TI_TIMEOUT 1000 #define TI_TXCONS_UNSET 0xFFFF /* impossible value */ -struct ti_mc_entry { - struct ether_addr mc_addr; - SLIST_ENTRY(ti_mc_entry) mc_entries; -}; - typedef enum { TI_FLAG_NONE = 0x00, TI_FLAG_DEBUGING = 0x01, @@ -1048,7 +1043,6 @@ int ti_std; /* current std ring head */ int ti_mini; /* current mini ring head */ int ti_jumbo; /* current jumo ring head */ - SLIST_HEAD(__ti_mchead, ti_mc_entry) ti_mc_listhead; uint32_t ti_stat_ticks; uint32_t ti_rx_coal_ticks; uint32_t ti_tx_coal_ticks; Index: sys/dev/tsec/if_tsec.c =================================================================== --- sys/dev/tsec/if_tsec.c +++ sys/dev/tsec/if_tsec.c @@ -1886,13 +1886,22 @@ m_adj(m, sizeof(struct tsec_rx_fcb)); } +static u_int +tsec_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t h, *hashtable = arg; + + h = (ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 24) & 0xFF; + hashtable[(h >> 5)] |= 1 << (0x1F - (h & 0x1F)); + + return (1); +} + static void tsec_setup_multicast(struct tsec_softc *sc) { uint32_t hashtable[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; struct ifnet *ifp = sc->tsec_ifp; - struct ifmultiaddr *ifma; - uint32_t h; int i; TSEC_GLOBAL_LOCK_ASSERT(sc); @@ -1904,18 +1913,7 @@ return; } - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - h = (ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 24) & 0xFF; - - hashtable[(h >> 5)] |= 1 << (0x1F - (h & 0x1F)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, tsec_hash_maddr, &hashtable); for (i = 0; i < 8; i++) TSEC_WRITE(sc, TSEC_REG_GADDR(i), hashtable[i]); Index: sys/dev/usb/net/if_aue.c =================================================================== --- sys/dev/usb/net/if_aue.c +++ sys/dev/usb/net/if_aue.c @@ -540,13 +540,23 @@ } #define AUE_BITS 6 +static u_int +aue_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint8_t *hashtbl = arg; + uint32_t h; + + h = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN) & ((1 << AUE_BITS) - 1); + hashtbl[(h >> 3)] |= 1 << (h & 0x7); + + return (1); +} + static void aue_setmulti(struct usb_ether *ue) { struct aue_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); - struct ifmultiaddr *ifma; - uint32_t h = 0; uint32_t i; uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -560,15 +570,7 @@ AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); /* now program new ones */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_le(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) & ((1 << AUE_BITS) - 1); - hashtbl[(h >> 3)] |= 1 << (h & 0x7); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, aue_hash_maddr, hashtbl); /* write the hashtable */ for (i = 0; i != 8; i++) Index: sys/dev/usb/net/if_axe.c =================================================================== --- sys/dev/usb/net/if_axe.c +++ sys/dev/usb/net/if_axe.c @@ -481,13 +481,23 @@ AXE_UNLOCK(sc); } +static u_int +axe_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint8_t *hashtbl = arg; + uint32_t h; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + hashtbl[h / 8] |= 1 << (h % 8); + + return (1); +} + static void axe_setmulti(struct usb_ether *ue) { struct axe_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); - struct ifmultiaddr *ifma; - uint32_t h = 0; uint16_t rxmode; uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -503,16 +513,7 @@ } rxmode &= ~AXE_RXCMD_ALLMULTI; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) - { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - hashtbl[h / 8] |= 1 << (h % 8); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, axe_hash_maddr, &hashtbl); axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl); axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); Index: sys/dev/usb/net/if_axge.c =================================================================== --- sys/dev/usb/net/if_axge.c +++ sys/dev/usb/net/if_axge.c @@ -756,19 +756,28 @@ mii_tick(mii); } +static u_int +axge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint8_t *hashtbl = arg; + uint32_t h; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + hashtbl[h / 8] |= 1 << (h % 8); + + return (1); +} + static void axge_rxfilter(struct usb_ether *ue) { struct axge_softc *sc; struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t h; uint16_t rxmode; uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; sc = uether_getsc(ue); ifp = uether_getifp(ue); - h = 0; AXGE_LOCK_ASSERT(sc, MA_OWNED); /* @@ -791,15 +800,7 @@ } rxmode |= RCR_ACPT_MCAST; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - hashtbl[h / 8] |= 1 << (h % 8); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, axge_hash_maddr, &hashtbl); axge_write_mem(sc, AXGE_ACCESS_MAC, 8, AXGE_MFA, (void *)&hashtbl, 8); axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode); Index: sys/dev/usb/net/if_cue.c =================================================================== --- sys/dev/usb/net/if_cue.c +++ sys/dev/usb/net/if_cue.c @@ -307,13 +307,24 @@ cue_setmulti(ue); } +static u_int +cue_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint8_t *hashtbl = arg; + uint32_t h; + + h = cue_mchash(LLADDR(sdl)); + hashtbl[h >> 3] |= 1 << (h & 0x7); + + return (1); +} + static void cue_setmulti(struct usb_ether *ue) { struct cue_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); - struct ifmultiaddr *ifma; - uint32_t h = 0, i; + uint32_t h, i; uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; CUE_LOCK_ASSERT(sc, MA_OWNED); @@ -327,15 +338,7 @@ } /* now program new ones */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) - { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = cue_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - hashtbl[h >> 3] |= 1 << (h & 0x7); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, cue_hash_maddr, hashtbl); /* * Also include the broadcast address in the filter Index: sys/dev/usb/net/if_kue.c =================================================================== --- sys/dev/usb/net/if_kue.c +++ sys/dev/usb/net/if_kue.c @@ -357,13 +357,25 @@ kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->sc_rxfilt); } +static u_int +kue_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct kue_softc *sc = arg; + + if (cnt >= KUE_MCFILTCNT(sc)) + return (1); + + memcpy(KUE_MCFILT(sc, cnt), LLADDR(sdl), ETHER_ADDR_LEN); + + return (1); +} + static void kue_setmulti(struct usb_ether *ue) { struct kue_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); - struct ifmultiaddr *ifma; - int i = 0; + int i; KUE_LOCK_ASSERT(sc, MA_OWNED); @@ -376,25 +388,9 @@ sc->sc_rxfilt &= ~KUE_RXFILT_ALLMULTI; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) - { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - /* - * If there are too many addresses for the - * internal filter, switch over to allmulti mode. - */ - if (i == KUE_MCFILTCNT(sc)) - break; - memcpy(KUE_MCFILT(sc, i), - LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - ETHER_ADDR_LEN); - i++; - } - if_maddr_runlock(ifp); + i = if_foreach_llmaddr(ifp, kue_copy_maddr, sc); - if (i == KUE_MCFILTCNT(sc)) + if (i >= KUE_MCFILTCNT(sc)) sc->sc_rxfilt |= KUE_RXFILT_ALLMULTI; else { sc->sc_rxfilt |= KUE_RXFILT_MULTICAST; Index: sys/dev/usb/net/if_mos.c =================================================================== --- sys/dev/usb/net/if_mos.c +++ sys/dev/usb/net/if_mos.c @@ -589,16 +589,23 @@ mos_reg_write_1(sc, MOS_CTL, rxmode); } +static u_int +mos_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint8_t *hashtbl = arg; + uint32_t h; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + hashtbl[h / 8] |= 1 << (h % 8); + return (1); +} static void mos_setmulti(struct usb_ether *ue) { struct mos_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); - struct ifmultiaddr *ifma; - - uint32_t h = 0; uint8_t rxmode; uint8_t hashtbl[8] = {0, 0, 0, 0, 0, 0, 0, 0}; int allmulti = 0; @@ -611,17 +618,7 @@ allmulti = 1; /* get all new ones */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) { - allmulti = 1; - continue; - } - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - hashtbl[h / 8] |= 1 << (h % 8); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, mos_hash_maddr, &hashtbl); /* now program new ones */ if (allmulti == 1) { Index: sys/dev/usb/net/if_muge.c =================================================================== --- sys/dev/usb/net/if_muge.c +++ sys/dev/usb/net/if_muge.c @@ -1862,6 +1862,24 @@ return (ether_crc32_be(addr, ETHER_ADDR_LEN) >> 23) & 0x1ff; } +static u_int +muge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct muge_softc *sc = arg; + uint32_t bitnum; + + /* First fill up the perfect address table. */ + if (cnt < 32 /* XXX */) + muge_set_addr_filter(sc, cnt + 1, LLADDR(sdl)); + else { + bitnum = muge_hash(LLADDR(sdl)); + sc->sc_mchash_table[bitnum / 32] |= (1 << (bitnum % 32)); + sc->sc_rfe_ctl |= ETH_RFE_CTL_MCAST_HASH_; + } + + return (1); +} + /** * muge_setmulti - Setup multicast * @ue: usb ethernet device context @@ -1877,8 +1895,7 @@ { struct muge_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); - uint8_t i, *addr; - struct ifmultiaddr *ifma; + uint8_t i; MUGE_LOCK_ASSERT(sc, MA_OWNED); @@ -1904,28 +1921,7 @@ muge_dbg_printf(sc, "receive all multicast enabled\n"); sc->sc_rfe_ctl |= ETH_RFE_CTL_MCAST_EN_; } else { - /* Lock the mac address list before hashing each of them. */ - if_maddr_rlock(ifp); - if (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) { - i = 1; - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, - ifma_link) { - /* First fill up the perfect address table. */ - addr = LLADDR((struct sockaddr_dl *) - ifma->ifma_addr); - if (i < 33 /* XXX */) { - muge_set_addr_filter(sc, i, addr); - } else { - uint32_t bitnum = muge_hash(addr); - sc->sc_mchash_table[bitnum / 32] |= - (1 << (bitnum % 32)); - sc->sc_rfe_ctl |= - ETH_RFE_CTL_MCAST_HASH_; - } - i++; - } - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, muge_hash_maddr, sc); muge_multicast_write(sc); } lan78xx_write_reg(sc, ETH_RFE_CTL, sc->sc_rfe_ctl); Index: sys/dev/usb/net/if_rue.c =================================================================== --- sys/dev/usb/net/if_rue.c +++ sys/dev/usb/net/if_rue.c @@ -473,6 +473,21 @@ RUE_CLRBIT(sc, RUE_RCR, RUE_RCR_AAP); } +static u_int +rue_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *hashes = arg; + int h; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + + return (1); +} + /* * Program the 64-bit multicast hash filter. */ @@ -482,10 +497,8 @@ struct rue_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); uint16_t rxcfg; - int h = 0; uint32_t hashes[2] = { 0, 0 }; - struct ifmultiaddr *ifma; - int mcnt = 0; + int mcnt; RUE_LOCK_ASSERT(sc, MA_OWNED); @@ -505,20 +518,7 @@ rue_csr_write_4(sc, RUE_MAR4, 0); /* now program new ones */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH (ifma, &ifp->if_multiaddrs, ifma_link) - { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - mcnt++; - } - if_maddr_runlock(ifp); + mcnt = if_foreach_llmaddr(ifp, rue_hash_maddr, &hashes); if (mcnt) rxcfg |= RUE_RCR_AM; Index: sys/dev/usb/net/if_smsc.c =================================================================== --- sys/dev/usb/net/if_smsc.c +++ sys/dev/usb/net/if_smsc.c @@ -691,6 +691,18 @@ return (ether_crc32_be(addr, ETHER_ADDR_LEN) >> 26) & 0x3f; } +static u_int +smsc_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t hash, *hashtbl = arg; + + hash = smsc_hash(LLADDR(sdl)); + hashtbl[hash >> 5] |= 1 << (hash & 0x1F); + + return (1); +} + + /** * smsc_setmulti - Setup multicast * @ue: usb ethernet device context @@ -706,9 +718,7 @@ { struct smsc_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); - struct ifmultiaddr *ifma; uint32_t hashtbl[2] = { 0, 0 }; - uint32_t hash; SMSC_LOCK_ASSERT(sc, MA_OWNED); @@ -718,29 +728,19 @@ sc->sc_mac_csr &= ~SMSC_MAC_CSR_HPFILT; } else { - /* Take the lock of the mac address list before hashing each of them */ - if_maddr_rlock(ifp); - - if (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) { - /* We are filtering on a set of address so calculate hashes of each - * of the address and set the corresponding bits in the register. + if (if_foreach_llmaddr(ifp, smsc_hash_maddr, &hashtbl) > 0) { + /* We are filtering on a set of address so calculate + * hashes of each of the address and set the + * corresponding bits in the register. */ sc->sc_mac_csr |= SMSC_MAC_CSR_HPFILT; sc->sc_mac_csr &= ~(SMSC_MAC_CSR_PRMS | SMSC_MAC_CSR_MCPAS); - - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - hash = smsc_hash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - hashtbl[hash >> 5] |= 1 << (hash & 0x1F); - } } else { - /* Only receive packets with destination set to our mac address */ + /* Only receive packets with destination set to + * our mac address + */ sc->sc_mac_csr &= ~(SMSC_MAC_CSR_MCPAS | SMSC_MAC_CSR_HPFILT); } - - if_maddr_runlock(ifp); /* Debug */ if (sc->sc_mac_csr & SMSC_MAC_CSR_HPFILT) Index: sys/dev/usb/net/if_udav.c =================================================================== --- sys/dev/usb/net/if_udav.c +++ sys/dev/usb/net/if_udav.c @@ -504,15 +504,24 @@ uether_pause(&sc->sc_ue, hz / 100); } -#define UDAV_BITS 6 +static u_int +udav_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint8_t *hashtbl = arg; + int h; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + hashtbl[h / 8] |= 1 << (h % 8); + + return (1); +} + static void udav_setmulti(struct usb_ether *ue) { struct udav_softc *sc = ue->ue_sc; struct ifnet *ifp = uether_getifp(&sc->sc_ue); - struct ifmultiaddr *ifma; uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - int h = 0; UDAV_LOCK_ASSERT(sc, MA_OWNED); @@ -527,16 +536,7 @@ udav_csr_write(sc, UDAV_MAR, hashtbl, sizeof(hashtbl)); /* now program new ones */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) - { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - hashtbl[h / 8] |= 1 << (h % 8); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, udav_hash_maddr, hashtbl); /* disable all multicast */ UDAV_CLRBIT(sc, UDAV_RCR, UDAV_RCR_ALL); Index: sys/dev/usb/net/if_ure.c =================================================================== --- sys/dev/usb/net/if_ure.c +++ sys/dev/usb/net/if_ure.c @@ -792,6 +792,19 @@ } } +static u_int +ure_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t h, *hashes = arg; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + return (1); +} + /* * Program the 64-bit multicast hash filter. */ @@ -800,9 +813,8 @@ { struct ure_softc *sc = uether_getsc(ue); struct ifnet *ifp = uether_getifp(ue); - struct ifmultiaddr *ifma; - uint32_t h, rxmode; - uint32_t hashes[2] = { 0, 0 }; + uint32_t rxmode; + uint32_t h, hashes[2] = { 0, 0 }; URE_LOCK_ASSERT(sc, MA_OWNED); @@ -818,18 +830,7 @@ } rxmode |= URE_RCR_AM; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, ure_hash_maddr, &hashes); h = bswap32(hashes[0]); hashes[0] = bswap32(hashes[1]); Index: sys/dev/usb/wlan/if_rsu.c =================================================================== --- sys/dev/usb/wlan/if_rsu.c +++ sys/dev/usb/wlan/if_rsu.c @@ -857,6 +857,18 @@ return (pos); } +static u_int +rsu_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *mfilt = arg; + uint8_t pos; + + pos = rsu_get_multi_pos(LLADDR(sdl)); + mfilt[pos / 32] |= (1 << (pos % 32)); + + return (1); +} + static void rsu_set_multi(struct rsu_softc *sc) { @@ -868,28 +880,13 @@ /* general structure was copied from ath(4). */ if (ic->ic_allmulti == 0) { struct ieee80211vap *vap; - struct ifnet *ifp; - struct ifmultiaddr *ifma; /* * Merge multicast addresses to form the hardware filter. */ mfilt[0] = mfilt[1] = 0; - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - ifp = vap->iv_ifp; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - caddr_t dl; - uint8_t pos; - - dl = LLADDR((struct sockaddr_dl *) - ifma->ifma_addr); - pos = rsu_get_multi_pos(dl); - - mfilt[pos / 32] |= (1 << (pos % 32)); - } - if_maddr_runlock(ifp); - } + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if_foreach_llmaddr(vap->iv_ifp, rsu_hash_maddr, &mfilt); } else mfilt[0] = mfilt[1] = ~0; Index: sys/dev/usb/wlan/if_zyd.c =================================================================== --- sys/dev/usb/wlan/if_zyd.c +++ sys/dev/usb/wlan/if_zyd.c @@ -1970,49 +1970,48 @@ return (error); } +static u_int +zyd_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *hash = arg; + uint8_t v; + + v = ((uint8_t *)LLADDR(sdl))[5] >> 2; + if (v < 32) + hash[0] |= 1 << v; + else + hash[1] |= 1 << (v - 32); + + return (1); +} + static void zyd_set_multi(struct zyd_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; - uint32_t low, high; + uint32_t hash[2]; int error; if ((sc->sc_flags & ZYD_FLAG_RUNNING) == 0) return; - low = 0x00000000; - high = 0x80000000; + hash[0] = 0x00000000; + hash[1] = 0x80000000; if (ic->ic_opmode == IEEE80211_M_MONITOR || ic->ic_allmulti > 0 || ic->ic_promisc > 0) { - low = 0xffffffff; - high = 0xffffffff; + hash[0] = 0xffffffff; + hash[1] = 0xffffffff; } else { struct ieee80211vap *vap; - struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint8_t v; - - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - ifp = vap->iv_ifp; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - v = ((uint8_t *)LLADDR((struct sockaddr_dl *) - ifma->ifma_addr))[5] >> 2; - if (v < 32) - low |= 1 << v; - else - high |= 1 << (v - 32); - } - if_maddr_runlock(ifp); - } + + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + if_foreach_llmaddr(vap->iv_ifp, zyd_hash_maddr, &hash); } /* reprogram multicast global hash table */ - zyd_write32_m(sc, ZYD_MAC_GHTBL, low); - zyd_write32_m(sc, ZYD_MAC_GHTBH, high); + zyd_write32_m(sc, ZYD_MAC_GHTBL, hash[0]); + zyd_write32_m(sc, ZYD_MAC_GHTBH, hash[1]); fail: if (error != 0) device_printf(sc->sc_dev, Index: sys/dev/vge/if_vge.c =================================================================== --- sys/dev/vge/if_vge.c +++ sys/dev/vge/if_vge.c @@ -529,6 +529,34 @@ CSR_WRITE_1(sc, VGE_RXCFG, cfg); } +static u_int +vge_set_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct vge_softc *sc = arg; + + if (sc->vge_camidx == VGE_CAM_MAXADDRS) + return (0); + + (void )vge_cam_set(sc, LLADDR(sdl)); + + return (1); +} + +static u_int +vge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t h, *hashes = arg; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + + return (1); +} + + /* * Program the multicast filter. We use the 64-entry CAM filter * for perfect filtering. If there's more than 64 multicast addresses, @@ -538,10 +566,8 @@ vge_rxfilter(struct vge_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint32_t h, hashes[2]; + uint32_t hashes[2]; uint8_t rxcfg; - int error = 0; VGE_LOCK_ASSERT(sc); @@ -572,33 +598,15 @@ } vge_cam_clear(sc); + /* Now program new ones */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - error = vge_cam_set(sc, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - if (error) - break; - } + if_foreach_llmaddr(ifp, vge_set_maddr, sc); /* If there were too many addresses, use the hash filter. */ - if (error) { + if (sc->vge_camidx == VGE_CAM_MAXADDRS) { vge_cam_clear(sc); - - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - } + if_foreach_llmaddr(ifp, vge_hash_maddr, hashes); } - if_maddr_runlock(ifp); done: if (hashes[0] != 0 || hashes[1] != 0) Index: sys/dev/virtio/network/if_vtnet.c =================================================================== --- sys/dev/virtio/network/if_vtnet.c +++ sys/dev/virtio/network/if_vtnet.c @@ -3285,6 +3285,34 @@ ifp->if_flags & IFF_ALLMULTI ? "enable" : "disable"); } +static u_int +vtnet_copy_ifaddr(void *arg, struct sockaddr_dl *sdl, u_int ucnt) +{ + struct vtnet_softc *sc = arg; + + if (memcmp(LLADDR(sdl), sc->vtnet_hwaddr, ETHER_ADDR_LEN) == 0) + return (0); + + if (ucnt < VTNET_MAX_MAC_ENTRIES) + bcopy(LLADDR(sdl), + &sc->vtnet_mac_filter->vmf_unicast.macs[ucnt], + ETHER_ADDR_LEN); + + return (1); +} + +static u_int +vtnet_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int mcnt) +{ + struct vtnet_mac_filter *filter = arg; + + if (mcnt < VTNET_MAX_MAC_ENTRIES) + bcopy(LLADDR(sdl), &filter->vmf_multicast.macs[mcnt], + ETHER_ADDR_LEN); + + return (1); +} + static void vtnet_rx_filter_mac(struct vtnet_softc *sc) { @@ -3293,42 +3321,23 @@ struct sglist_seg segs[4]; struct sglist sg; struct ifnet *ifp; - struct ifaddr *ifa; - struct ifmultiaddr *ifma; - int ucnt, mcnt, promisc, allmulti, error; + bool promisc, allmulti; + u_int ucnt, mcnt; + int error; uint8_t ack; ifp = sc->vtnet_ifp; filter = sc->vtnet_mac_filter; - ucnt = 0; - mcnt = 0; - promisc = 0; - allmulti = 0; VTNET_CORE_LOCK_ASSERT(sc); KASSERT(sc->vtnet_flags & VTNET_FLAG_CTRL_RX, ("%s: CTRL_RX feature not negotiated", __func__)); /* Unicast MAC addresses: */ - if_addr_rlock(ifp); - CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - if (ifa->ifa_addr->sa_family != AF_LINK) - continue; - else if (memcmp(LLADDR((struct sockaddr_dl *)ifa->ifa_addr), - sc->vtnet_hwaddr, ETHER_ADDR_LEN) == 0) - continue; - else if (ucnt == VTNET_MAX_MAC_ENTRIES) { - promisc = 1; - break; - } + ucnt = if_foreach_lladdr(ifp, vtnet_copy_ifaddr, sc); + promisc = (ucnt > VTNET_MAX_MAC_ENTRIES); - bcopy(LLADDR((struct sockaddr_dl *)ifa->ifa_addr), - &filter->vmf_unicast.macs[ucnt], ETHER_ADDR_LEN); - ucnt++; - } - if_addr_runlock(ifp); - - if (promisc != 0) { + if (promisc) { filter->vmf_unicast.nentries = 0; if_printf(ifp, "more than %d MAC addresses assigned, " "falling back to promiscuous mode\n", @@ -3337,22 +3346,10 @@ filter->vmf_unicast.nentries = ucnt; /* Multicast MAC addresses: */ - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - else if (mcnt == VTNET_MAX_MAC_ENTRIES) { - allmulti = 1; - break; - } - - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - &filter->vmf_multicast.macs[mcnt], ETHER_ADDR_LEN); - mcnt++; - } - if_maddr_runlock(ifp); + mcnt = if_foreach_llmaddr(ifp, vtnet_copy_maddr, filter); + allmulti = (mcnt > VTNET_MAX_MAC_ENTRIES); - if (allmulti != 0) { + if (allmulti) { filter->vmf_multicast.nentries = 0; if_printf(ifp, "more than %d multicast MAC addresses " "assigned, falling back to all-multicast mode\n", @@ -3360,7 +3357,7 @@ } else filter->vmf_multicast.nentries = mcnt; - if (promisc != 0 && allmulti != 0) + if (promisc && allmulti) goto out; hdr.class = VIRTIO_NET_CTRL_MAC; Index: sys/dev/vmware/vmxnet3/if_vmx.c =================================================================== --- sys/dev/vmware/vmxnet3/if_vmx.c +++ sys/dev/vmware/vmxnet3/if_vmx.c @@ -1995,12 +1995,23 @@ vmxnet3_update_vlan_filter(iflib_get_softc(ctx), 0, tag); } +static u_int +vmxnet3_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int count) +{ + struct vmxnet3_softc *sc = arg; + + if (count < VMXNET3_MULTICAST_MAX) + bcopy(LLADDR(sdl), &sc->vmx_mcast[count * ETHER_ADDR_LEN], + ETHER_ADDR_LEN); + + return (1); +} + static void vmxnet3_set_rxfilter(struct vmxnet3_softc *sc, int flags) { struct ifnet *ifp; struct vmxnet3_driver_shared *ds; - struct ifmultiaddr *ifma; u_int mode; ifp = sc->vmx_ifp; @@ -2012,24 +2023,10 @@ if (flags & IFF_ALLMULTI) mode |= VMXNET3_RXMODE_ALLMULTI; else { - int cnt = 0, overflow = 0; - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - else if (cnt == VMXNET3_MULTICAST_MAX) { - overflow = 1; - break; - } - - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - &sc->vmx_mcast[cnt*ETHER_ADDR_LEN], ETHER_ADDR_LEN); - cnt++; - } - if_maddr_runlock(ifp); + int cnt; - if (overflow != 0) { + cnt = if_foreach_llmaddr(ifp, vmxnet3_hash_maddr, sc); + if (cnt >= VMXNET3_MULTICAST_MAX) { cnt = 0; mode |= VMXNET3_RXMODE_ALLMULTI; } else if (cnt > 0) Index: sys/dev/vr/if_vr.c =================================================================== --- sys/dev/vr/if_vr.c +++ sys/dev/vr/if_vr.c @@ -432,6 +432,44 @@ return (i == VR_TIMEOUT ? ETIMEDOUT : 0); } +struct vr_hash_maddr_cam_ctx { + struct vr_softc *sc; + uint32_t mask; + int error; +}; + +static u_int +vr_hash_maddr_cam(void *arg, struct sockaddr_dl *sdl, u_int mcnt) +{ + struct vr_hash_maddr_cam_ctx *ctx = arg; + + if (ctx->error != 0) + return (0); + ctx->error = vr_cam_data(ctx->sc, VR_MCAST_CAM, mcnt, LLADDR(sdl)); + if (ctx->error != 0) { + ctx->mask = 0; + return (0); + } + ctx->mask |= 1 << mcnt; + + return (1); +} + +static u_int +vr_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint32_t *hashes = arg; + int h; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26; + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + + return (1); +} + /* * Program the 64-bit multicast hash filter. */ @@ -439,12 +477,9 @@ vr_set_filter(struct vr_softc *sc) { struct ifnet *ifp; - int h; uint32_t hashes[2] = { 0, 0 }; - struct ifmultiaddr *ifma; uint8_t rxfilt; int error, mcnt; - uint32_t cam_mask; VR_LOCK_ASSERT(sc); @@ -466,27 +501,18 @@ /* Now program new ones. */ error = 0; - mcnt = 0; - if_maddr_rlock(ifp); if ((sc->vr_quirks & VR_Q_CAM) != 0) { + struct vr_hash_maddr_cam_ctx ctx; + /* * For hardwares that have CAM capability, use * 32 entries multicast perfect filter. */ - cam_mask = 0; - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - error = vr_cam_data(sc, VR_MCAST_CAM, mcnt, - LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); - if (error != 0) { - cam_mask = 0; - break; - } - cam_mask |= 1 << mcnt; - mcnt++; - } - vr_cam_mask(sc, VR_MCAST_CAM, cam_mask); + ctx.sc = sc; + ctx.mask = 0; + ctx.error = 0; + mcnt = if_foreach_llmaddr(ifp, vr_hash_maddr_cam, &ctx); + vr_cam_mask(sc, VR_MCAST_CAM, ctx.mask); } if ((sc->vr_quirks & VR_Q_CAM) == 0 || error != 0) { @@ -495,20 +521,8 @@ * setting multicast CAM filter failed, use hash * table based filtering. */ - mcnt = 0; - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - mcnt++; - } + mcnt = if_foreach_llmaddr(ifp, vr_hash_maddr, hashes); } - if_maddr_runlock(ifp); if (mcnt > 0) rxfilt |= VR_RXCFG_RX_MULTI; Index: sys/dev/vte/if_vte.c =================================================================== --- sys/dev/vte/if_vte.c +++ sys/dev/vte/if_vte.c @@ -1955,27 +1955,57 @@ return (0); } +struct vte_maddr_ctx { + uint16_t rxfilt_perf[VTE_RXFILT_PERFECT_CNT][3]; + uint16_t mchash[4]; + u_int nperf; +}; + +static u_int +vte_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct vte_maddr_ctx *ctx = arg; + uint8_t *eaddr; + uint32_t crc; + + /* + * Program the first 3 multicast groups into the perfect filter. + * For all others, use the hash table. + */ + if (ctx->nperf < VTE_RXFILT_PERFECT_CNT) { + eaddr = LLADDR(sdl); + ctx->rxfilt_perf[ctx->nperf][0] = eaddr[1] << 8 | eaddr[0]; + ctx->rxfilt_perf[ctx->nperf][1] = eaddr[3] << 8 | eaddr[2]; + ctx->rxfilt_perf[ctx->nperf][2] = eaddr[5] << 8 | eaddr[4]; + ctx->nperf++; + + return (1); + } + crc = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN); + ctx->mchash[crc >> 30] |= 1 << ((crc >> 26) & 0x0F); + + return (1); +} + static void vte_rxfilter(struct vte_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - uint8_t *eaddr; - uint32_t crc; - uint16_t rxfilt_perf[VTE_RXFILT_PERFECT_CNT][3]; - uint16_t mchash[4], mcr; - int i, nperf; + struct vte_maddr_ctx ctx; + uint16_t mcr; + int i; VTE_LOCK_ASSERT(sc); ifp = sc->vte_ifp; - bzero(mchash, sizeof(mchash)); + bzero(ctx.mchash, sizeof(ctx.mchash)); for (i = 0; i < VTE_RXFILT_PERFECT_CNT; i++) { - rxfilt_perf[i][0] = 0xFFFF; - rxfilt_perf[i][1] = 0xFFFF; - rxfilt_perf[i][2] = 0xFFFF; + ctx.rxfilt_perf[i][0] = 0xFFFF; + ctx.rxfilt_perf[i][1] = 0xFFFF; + ctx.rxfilt_perf[i][2] = 0xFFFF; } + ctx.nperf = 0; mcr = CSR_READ_2(sc, VTE_MCR0); mcr &= ~(MCR0_PROMISC | MCR0_MULTICAST); @@ -1987,54 +2017,32 @@ mcr |= MCR0_PROMISC; if ((ifp->if_flags & IFF_ALLMULTI) != 0) mcr |= MCR0_MULTICAST; - mchash[0] = 0xFFFF; - mchash[1] = 0xFFFF; - mchash[2] = 0xFFFF; - mchash[3] = 0xFFFF; + ctx.mchash[0] = 0xFFFF; + ctx.mchash[1] = 0xFFFF; + ctx.mchash[2] = 0xFFFF; + ctx.mchash[3] = 0xFFFF; goto chipit; } - nperf = 0; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &sc->vte_ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - /* - * Program the first 3 multicast groups into - * the perfect filter. For all others, use the - * hash table. - */ - if (nperf < VTE_RXFILT_PERFECT_CNT) { - eaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); - rxfilt_perf[nperf][0] = eaddr[1] << 8 | eaddr[0]; - rxfilt_perf[nperf][1] = eaddr[3] << 8 | eaddr[2]; - rxfilt_perf[nperf][2] = eaddr[5] << 8 | eaddr[4]; - nperf++; - continue; - } - crc = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN); - mchash[crc >> 30] |= 1 << ((crc >> 26) & 0x0F); - } - if_maddr_runlock(ifp); - if (mchash[0] != 0 || mchash[1] != 0 || mchash[2] != 0 || - mchash[3] != 0) + if_foreach_llmaddr(ifp, vte_hash_maddr, &ctx); + if (ctx.mchash[0] != 0 || ctx.mchash[1] != 0 || + ctx.mchash[2] != 0 || ctx.mchash[3] != 0) mcr |= MCR0_MULTICAST; chipit: /* Program multicast hash table. */ - CSR_WRITE_2(sc, VTE_MAR0, mchash[0]); - CSR_WRITE_2(sc, VTE_MAR1, mchash[1]); - CSR_WRITE_2(sc, VTE_MAR2, mchash[2]); - CSR_WRITE_2(sc, VTE_MAR3, mchash[3]); + CSR_WRITE_2(sc, VTE_MAR0, ctx.mchash[0]); + CSR_WRITE_2(sc, VTE_MAR1, ctx.mchash[1]); + CSR_WRITE_2(sc, VTE_MAR2, ctx.mchash[2]); + CSR_WRITE_2(sc, VTE_MAR3, ctx.mchash[3]); /* Program perfect filter table. */ for (i = 0; i < VTE_RXFILT_PERFECT_CNT; i++) { CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 0, - rxfilt_perf[i][0]); + ctx.rxfilt_perf[i][0]); CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 2, - rxfilt_perf[i][1]); + ctx.rxfilt_perf[i][1]); CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 4, - rxfilt_perf[i][2]); + ctx.rxfilt_perf[i][2]); } CSR_WRITE_2(sc, VTE_MCR0, mcr); CSR_READ_2(sc, VTE_MCR0); Index: sys/dev/wi/if_wi.c =================================================================== --- sys/dev/wi/if_wi.c +++ sys/dev/wi/if_wi.c @@ -1506,41 +1506,45 @@ CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO); } +struct wi_mcast_ctx { + struct wi_mcast mlist; + int mcnt; +}; + +static u_int +wi_copy_mcast(void *arg, struct sockaddr_dl *sdl, u_int count) +{ + struct wi_mcast_ctx *ctx = arg; + + if (ctx->mcnt >= 16) + return (0); + IEEE80211_ADDR_COPY(&ctx->mlist.wi_mcast[ctx->mcnt++], LLADDR(sdl)); + + return (1); +} + static int wi_write_multi(struct wi_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap; - struct wi_mcast mlist; - int n; + struct wi_mcast_ctx ctx; if (ic->ic_allmulti > 0 || ic->ic_promisc > 0) { allmulti: - memset(&mlist, 0, sizeof(mlist)); - return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist, - sizeof(mlist)); + memset(&ctx.mlist, 0, sizeof(ctx.mlist)); + return wi_write_rid(sc, WI_RID_MCAST_LIST, &ctx.mlist, + sizeof(ctx.mlist)); } - n = 0; + ctx.mcnt = 0; TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - struct ifnet *ifp; - struct ifmultiaddr *ifma; - - ifp = vap->iv_ifp; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - if (n >= 16) - goto allmulti; - IEEE80211_ADDR_COPY(&mlist.wi_mcast[n], - (LLADDR((struct sockaddr_dl *)ifma->ifma_addr))); - n++; - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(vap->iv_ifp, wi_copy_mcast, &ctx); + if (ctx.mcnt >= 16) + goto allmulti; } - return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist, - IEEE80211_ADDR_LEN * n); + return wi_write_rid(sc, WI_RID_MCAST_LIST, &ctx.mlist, + IEEE80211_ADDR_LEN * ctx.mcnt); } static void Index: sys/dev/xilinx/if_xae.c =================================================================== --- sys/dev/xilinx/if_xae.c +++ sys/dev/xilinx/if_xae.c @@ -514,14 +514,40 @@ return (error); } +static u_int +xae_write_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct xae_softc *sc = arg; + uint32_t reg; + uint8_t *ma; + + if (cnt >= XAE_MULTICAST_TABLE_SIZE) + return (1); + + ma = LLADDR(sdl); + + reg = READ4(sc, XAE_FFC) & 0xffffff00; + reg |= cnt; + WRITE4(sc, XAE_FFC, reg); + + reg = (ma[0]); + reg |= (ma[1] << 8); + reg |= (ma[2] << 16); + reg |= (ma[3] << 24); + WRITE4(sc, XAE_FFV(0), reg); + + reg = ma[4]; + reg |= ma[5] << 8; + WRITE4(sc, XAE_FFV(1), reg); + + return (1); +} + static void xae_setup_rxfilter(struct xae_softc *sc) { - struct ifmultiaddr *ifma; struct ifnet *ifp; uint32_t reg; - uint8_t *ma; - int i; XAE_ASSERT_LOCKED(sc); @@ -539,33 +565,7 @@ reg &= ~FFC_PM; WRITE4(sc, XAE_FFC, reg); - if_maddr_rlock(ifp); - - i = 0; - CK_STAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - if (i >= XAE_MULTICAST_TABLE_SIZE) - break; - - ma = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); - - reg = READ4(sc, XAE_FFC) & 0xffffff00; - reg |= i++; - WRITE4(sc, XAE_FFC, reg); - - reg = (ma[0]); - reg |= (ma[1] << 8); - reg |= (ma[2] << 16); - reg |= (ma[3] << 24); - WRITE4(sc, XAE_FFV(0), reg); - - reg = ma[4]; - reg |= ma[5] << 8; - WRITE4(sc, XAE_FFV(1), reg); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, xae_write_maddr, sc); } /* Index: sys/dev/xl/if_xl.c =================================================================== --- sys/dev/xl/if_xl.c +++ sys/dev/xl/if_xl.c @@ -606,11 +606,20 @@ * NICs older than the 3c905B have only one multicast option, which * is to enable reception of all multicast frames. */ +static u_int +xl_check_maddr_90x(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + uint8_t *rxfilt = arg; + + *rxfilt |= XL_RXFILTER_ALLMULTI; + + return (1); +} + static void xl_rxfilter_90x(struct xl_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; u_int8_t rxfilt; XL_LOCK_ASSERT(sc); @@ -634,16 +643,8 @@ rxfilt |= XL_RXFILTER_ALLFRAMES; if (ifp->if_flags & IFF_ALLMULTI) rxfilt |= XL_RXFILTER_ALLMULTI; - } else { - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - rxfilt |= XL_RXFILTER_ALLMULTI; - break; - } - if_maddr_runlock(ifp); - } + } else + if_foreach_llmaddr(sc->xl_ifp, xl_check_maddr_90x, &rxfilt); CSR_WRITE_2(sc, XL_COMMAND, rxfilt | XL_CMD_RX_SET_FILT); XL_SEL_WIN(7); @@ -651,14 +652,34 @@ /* * 3c905B adapters have a hash filter that we can program. + * Note: the 3c905B currently only supports a 64-bit + * hash table, which means we really only need 6 bits, + * but the manual indicates that future chip revisions + * will have a 256-bit hash table, hence the routine + * is set up to calculate 8 bits of position info in + * case we need it some day. + * Note II, The Sequel: _CURRENT_ versions of the + * 3c905B have a 256 bit hash table. This means we have + * to use all 8 bits regardless. On older cards, the + * upper 2 bits will be ignored. Grrrr.... */ +static u_int +xl_check_maddr_90xB(void *arg, struct sockaddr_dl *sdl, u_int count) +{ + struct xl_softc *sc = arg; + uint16_t h; + + h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) & 0xFF; + CSR_WRITE_2(sc, XL_COMMAND, h | XL_CMD_RX_SET_HASH | XL_HASH_SET); + + return (1); +} + static void xl_rxfilter_90xB(struct xl_softc *sc) { struct ifnet *ifp; - struct ifmultiaddr *ifma; - int i, mcnt; - u_int16_t h; + int i; u_int8_t rxfilt; XL_LOCK_ASSERT(sc); @@ -689,31 +710,7 @@ CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_HASH | i); /* Now program new ones. */ - mcnt = 0; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - /* - * Note: the 3c905B currently only supports a 64-bit - * hash table, which means we really only need 6 bits, - * but the manual indicates that future chip revisions - * will have a 256-bit hash table, hence the routine - * is set up to calculate 8 bits of position info in - * case we need it some day. - * Note II, The Sequel: _CURRENT_ versions of the - * 3c905B have a 256 bit hash table. This means we have - * to use all 8 bits regardless. On older cards, the - * upper 2 bits will be ignored. Grrrr.... - */ - h = ether_crc32_be(LLADDR((struct sockaddr_dl *) - ifma->ifma_addr), ETHER_ADDR_LEN) & 0xFF; - CSR_WRITE_2(sc, XL_COMMAND, - h | XL_CMD_RX_SET_HASH | XL_HASH_SET); - mcnt++; - } - if_maddr_runlock(ifp); - if (mcnt > 0) + if (if_foreach_llmaddr(sc->xl_ifp, xl_check_maddr_90xB, sc) > 0) rxfilt |= XL_RXFILTER_MULTIHASH; } Index: sys/kern/init_main.c =================================================================== --- sys/kern/init_main.c +++ sys/kern/init_main.c @@ -514,7 +514,6 @@ td->td_pflags = TDP_KTHREAD; td->td_cpuset = cpuset_thread0(); td->td_domain.dr_policy = td->td_cpuset->cs_domain; - epoch_thread_init(td); prison0_init(); p->p_peers = 0; p->p_leader = p; Index: sys/kern/kern_thread.c =================================================================== --- sys/kern/kern_thread.c +++ sys/kern/kern_thread.c @@ -273,7 +273,6 @@ td->td_rlqe = NULL; EVENTHANDLER_DIRECT_INVOKE(thread_init, td); umtx_thread_init(td); - epoch_thread_init(td); td->td_kstack = 0; td->td_sel = NULL; return (0); @@ -293,7 +292,6 @@ turnstile_free(td->td_turnstile); sleepq_free(td->td_sleepqueue); umtx_thread_fini(td); - epoch_thread_fini(td); seltdfini(td); } Index: sys/kern/subr_epoch.c =================================================================== --- sys/kern/subr_epoch.c +++ sys/kern/subr_epoch.c @@ -829,17 +829,3 @@ PICKUP_GIANT(); } - -void -epoch_thread_init(struct thread *td) -{ - - td->td_et = malloc(sizeof(struct epoch_tracker), M_EPOCH, M_WAITOK); -} - -void -epoch_thread_fini(struct thread *td) -{ - - free(td->td_et, M_EPOCH); -} Index: sys/net/if.c =================================================================== --- sys/net/if.c +++ sys/net/if.c @@ -1775,40 +1775,6 @@ ifd->ifi_noproto = ifp->if_get_counter(ifp, IFCOUNTER_NOPROTO); } -/* - * Wrapper functions for struct ifnet address list locking macros. These are - * used by kernel modules to avoid encoding programming interface or binary - * interface assumptions that may be violated when kernel-internal locking - * approaches change. - */ -void -if_addr_rlock(struct ifnet *ifp) -{ - - epoch_enter_preempt(net_epoch_preempt, curthread->td_et); -} - -void -if_addr_runlock(struct ifnet *ifp) -{ - - epoch_exit_preempt(net_epoch_preempt, curthread->td_et); -} - -void -if_maddr_rlock(if_t ifp) -{ - - epoch_enter_preempt(net_epoch_preempt, curthread->td_et); -} - -void -if_maddr_runlock(if_t ifp) -{ - - epoch_exit_preempt(net_epoch_preempt, curthread->td_et); -} - /* * Initialization, destruction and refcounting functions for ifaddrs. */ @@ -4272,6 +4238,83 @@ return (((struct ifnet *)ifp)->if_mtu); } +/* + * Methods for drivers to access interface unicast and multicast + * link level addresses. Driver shall not know 'struct ifaddr' neither + * 'struct ifmultiaddr'. + */ +u_int +if_lladdr_count(if_t ifp) +{ + struct epoch_tracker et; + struct ifaddr *ifa; + u_int count; + + count = 0; + NET_EPOCH_ENTER(et); + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) + if (ifa->ifa_addr->sa_family == AF_LINK) + count++; + NET_EPOCH_EXIT(et); + + return (count); +} + +u_int +if_foreach_lladdr(if_t ifp, iflladdr_cb_t cb, void *cb_arg) +{ + struct epoch_tracker et; + struct ifaddr *ifa; + u_int count = 0; + + NET_EPOCH_ENTER(et); + CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr->sa_family != AF_LINK) + continue; + count += (*cb)(cb_arg, (struct sockaddr_dl *)ifa->ifa_addr, + count); + } + NET_EPOCH_EXIT(et); + + return (count); +} + +u_int +if_llmaddr_count(if_t ifp) +{ + struct epoch_tracker et; + struct ifmultiaddr *ifma; + int count; + + count = 0; + NET_EPOCH_ENTER(et); + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) + if (ifma->ifma_addr->sa_family == AF_LINK) + count++; + NET_EPOCH_EXIT(et); + + return (count); +} + +u_int +if_foreach_llmaddr(if_t ifp, iflladdr_cb_t cb, void *cb_arg) +{ + struct epoch_tracker et; + struct ifmultiaddr *ifma; + u_int count = 0; + + NET_EPOCH_ENTER(et); + CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + count += (*cb)(cb_arg, (struct sockaddr_dl *)ifma->ifma_addr, + count); + } + NET_EPOCH_EXIT(et); + + return (count); +} + int if_setsoftc(if_t ifp, void *softc) { @@ -4355,77 +4398,6 @@ } -/* XXX */ -#ifndef ETH_ADDR_LEN -#define ETH_ADDR_LEN 6 -#endif - -int -if_setupmultiaddr(if_t ifp, void *mta, int *cnt, int max) -{ - struct ifmultiaddr *ifma; - uint8_t *lmta = (uint8_t *)mta; - int mcnt = 0; - - CK_STAILQ_FOREACH(ifma, &((struct ifnet *)ifp)->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - - if (mcnt == max) - break; - - bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), - &lmta[mcnt * ETH_ADDR_LEN], ETH_ADDR_LEN); - mcnt++; - } - *cnt = mcnt; - - return (0); -} - -int -if_multiaddr_array(if_t ifp, void *mta, int *cnt, int max) -{ - int error; - - if_maddr_rlock(ifp); - error = if_setupmultiaddr(ifp, mta, cnt, max); - if_maddr_runlock(ifp); - return (error); -} - -int -if_multiaddr_count(if_t ifp, int max) -{ - struct ifmultiaddr *ifma; - int count; - - count = 0; - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &((struct ifnet *)ifp)->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - count++; - if (count == max) - break; - } - if_maddr_runlock(ifp); - return (count); -} - -int -if_multi_apply(struct ifnet *ifp, int (*filter)(void *, struct ifmultiaddr *, int), void *arg) -{ - struct ifmultiaddr *ifma; - int cnt = 0; - - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) - cnt += filter(arg, ifma, cnt); - if_maddr_runlock(ifp); - return (cnt); -} - struct mbuf * if_dequeue(if_t ifp) { Index: sys/net/if_spppsubr.c =================================================================== --- sys/net/if_spppsubr.c +++ sys/net/if_spppsubr.c @@ -4818,6 +4818,7 @@ void sppp_get_ip_addrs(struct sppp *sp, u_long *src, u_long *dst, u_long *srcmask) { + struct epoch_tracker et; struct ifnet *ifp = SP2IFP(sp); struct ifaddr *ifa; struct sockaddr_in *si, *sm; @@ -4830,7 +4831,7 @@ * aliases don't make any sense on a p2p link anyway. */ si = NULL; - if_addr_rlock(ifp); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (ifa->ifa_addr->sa_family == AF_INET) { si = (struct sockaddr_in *)ifa->ifa_addr; @@ -4849,7 +4850,7 @@ if (si && si->sin_addr.s_addr) ddst = si->sin_addr.s_addr; } - if_addr_runlock(ifp); + NET_EPOCH_EXIT(et); if (dst) *dst = ntohl(ddst); if (src) *src = ntohl(ssrc); @@ -4863,6 +4864,7 @@ sppp_set_ip_addr(struct sppp *sp, u_long src) { STDDCL; + struct epoch_tracker et; struct ifaddr *ifa; struct sockaddr_in *si; struct in_ifaddr *ia; @@ -4872,7 +4874,7 @@ * aliases don't make any sense on a p2p link anyway. */ si = NULL; - if_addr_rlock(ifp); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == AF_INET) { si = (struct sockaddr_in *)ifa->ifa_addr; @@ -4882,7 +4884,7 @@ } } } - if_addr_runlock(ifp); + NET_EPOCH_EXIT(et); if (ifa != NULL) { int error; @@ -4921,6 +4923,7 @@ sppp_get_ip6_addrs(struct sppp *sp, struct in6_addr *src, struct in6_addr *dst, struct in6_addr *srcmask) { + struct epoch_tracker et; struct ifnet *ifp = SP2IFP(sp); struct ifaddr *ifa; struct sockaddr_in6 *si, *sm; @@ -4934,7 +4937,7 @@ * aliases don't make any sense on a p2p link anyway. */ si = NULL; - if_addr_rlock(ifp); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) if (ifa->ifa_addr->sa_family == AF_INET6) { si = (struct sockaddr_in6 *)ifa->ifa_addr; @@ -4960,7 +4963,7 @@ bcopy(&ddst, dst, sizeof(*dst)); if (src) bcopy(&ssrc, src, sizeof(*src)); - if_addr_runlock(ifp); + NET_EPOCH_EXIT(et); } #ifdef IPV6CP_MYIFID_DYN @@ -4980,6 +4983,7 @@ sppp_set_ip6_addr(struct sppp *sp, const struct in6_addr *src) { STDDCL; + struct epoch_tracker et; struct ifaddr *ifa; struct sockaddr_in6 *sin6; @@ -4989,7 +4993,7 @@ */ sin6 = NULL; - if_addr_rlock(ifp); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == AF_INET6) { sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; @@ -4999,7 +5003,7 @@ } } } - if_addr_runlock(ifp); + NET_EPOCH_EXIT(et); if (ifa != NULL) { int error; Index: sys/net/if_stf.c =================================================================== --- sys/net/if_stf.c +++ sys/net/if_stf.c @@ -374,7 +374,8 @@ struct sockaddr_in6 *sin6; struct in_addr in; - if_addr_rlock(ifp); + NET_EPOCH_ASSERT(); + CK_STAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) { if (ia->ifa_addr->sa_family != AF_INET6) continue; @@ -395,10 +396,8 @@ *addr = sin6->sin6_addr; *mask = ia6->ia_prefixmask.sin6_addr; - if_addr_runlock(ifp); return (0); } - if_addr_runlock(ifp); return (ENOENT); } Index: sys/net/if_tuntap.c =================================================================== --- sys/net/if_tuntap.c +++ sys/net/if_tuntap.c @@ -1151,6 +1151,7 @@ { struct tuntap_softc *tp = ifp->if_softc; #ifdef INET + struct epoch_tracker et; struct ifaddr *ifa; #endif @@ -1162,7 +1163,7 @@ ifp->if_flags |= IFF_UP; getmicrotime(&ifp->if_lastchange); #ifdef INET - if_addr_rlock(ifp); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family == AF_INET) { struct sockaddr_in *si; @@ -1176,7 +1177,7 @@ tp->tun_flags |= TUN_DSTADDR; } } - if_addr_runlock(ifp); + NET_EPOCH_EXIT(et); #endif TUN_UNLOCK(tp); } else { Index: sys/net/if_var.h =================================================================== --- sys/net/if_var.h +++ sys/net/if_var.h @@ -449,16 +449,6 @@ #define NET_EPOCH_WAIT() epoch_wait_preempt(net_epoch_preempt) #define NET_EPOCH_ASSERT() MPASS(in_epoch(net_epoch_preempt)) -/* - * Function variations on locking macros intended to be used by loadable - * kernel modules in order to divorce them from the internals of address list - * locking. - */ -void if_addr_rlock(struct ifnet *ifp); /* if_addrhead */ -void if_addr_runlock(struct ifnet *ifp); /* if_addrhead */ -void if_maddr_rlock(if_t ifp); /* if_multiaddrs */ -void if_maddr_runlock(if_t ifp); /* if_multiaddrs */ - #ifdef _KERNEL /* interface link layer address change event */ typedef void (*iflladdr_event_handler_t)(void *, struct ifnet *); @@ -765,11 +755,16 @@ void if_etherbpfmtap(if_t ifp, struct mbuf *m); void if_vlancap(if_t ifp); -int if_setupmultiaddr(if_t ifp, void *mta, int *cnt, int max); -int if_multiaddr_array(if_t ifp, void *mta, int *cnt, int max); -int if_multiaddr_count(if_t ifp, int max); +/* + * Traversing through interface address lists. + */ +struct sockaddr_dl; +typedef u_int iflladdr_cb_t(void *, struct sockaddr_dl *, u_int); +u_int if_foreach_lladdr(if_t, iflladdr_cb_t, void *); +u_int if_foreach_llmaddr(if_t, iflladdr_cb_t, void *); +u_int if_lladdr_count(if_t); +u_int if_llmaddr_count(if_t); -int if_multi_apply(struct ifnet *ifp, int (*filter)(void *, struct ifmultiaddr *, int), void *arg); int if_getamcount(if_t ifp); struct ifaddr * if_getifaddr(if_t ifp); Index: sys/net80211/ieee80211_ioctl.c =================================================================== --- sys/net80211/ieee80211_ioctl.c +++ sys/net80211/ieee80211_ioctl.c @@ -3583,6 +3583,8 @@ IEEE80211_UNLOCK(ic); /* Wait for parent ioctl handler if it was queued */ if (wait) { + struct epoch_tracker et; + ieee80211_waitfor_parent(ic); /* @@ -3592,13 +3594,13 @@ * NB: device may be detached during initialization; * use if_ioctl for existence check. */ - if_addr_rlock(ifp); + NET_EPOCH_ENTER(et); if (ifp->if_ioctl == ieee80211_ioctl && (ifp->if_flags & IFF_UP) == 0 && !IEEE80211_ADDR_EQ(vap->iv_myaddr, IF_LLADDR(ifp))) IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp)); - if_addr_runlock(ifp); + NET_EPOCH_EXIT(et); } break; case SIOCADDMULTI: Index: sys/netgraph/ng_eiface.c =================================================================== --- sys/netgraph/ng_eiface.c +++ sys/netgraph/ng_eiface.c @@ -506,18 +506,19 @@ case NGM_EIFACE_GET_IFADDRS: { + struct epoch_tracker et; struct ifaddr *ifa; caddr_t ptr; int buflen; /* Determine size of response and allocate it */ buflen = 0; - if_addr_rlock(ifp); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) buflen += SA_SIZE(ifa->ifa_addr); NG_MKRESPONSE(resp, msg, buflen, M_NOWAIT); if (resp == NULL) { - if_addr_runlock(ifp); + NET_EPOCH_EXIT(et); error = ENOMEM; break; } @@ -536,7 +537,7 @@ ptr += len; buflen -= len; } - if_addr_runlock(ifp); + NET_EPOCH_EXIT(et); break; } Index: sys/netgraph/ng_ether.c =================================================================== --- sys/netgraph/ng_ether.c +++ sys/netgraph/ng_ether.c @@ -578,6 +578,7 @@ case NGM_ETHER_ADD_MULTI: { struct sockaddr_dl sa_dl; + struct epoch_tracker et; struct ifmultiaddr *ifma; if (msg->header.arglen != ETHER_ADDR_LEN) { @@ -597,16 +598,16 @@ * lose a race while we check if the membership * already exists. */ - if_maddr_rlock(priv->ifp); + NET_EPOCH_ENTER(et); ifma = if_findmulti(priv->ifp, (struct sockaddr *)&sa_dl); - if_maddr_runlock(priv->ifp); if (ifma != NULL) { error = EADDRINUSE; } else { error = if_addmulti(priv->ifp, (struct sockaddr *)&sa_dl, &ifma); } + NET_EPOCH_EXIT(et); break; } case NGM_ETHER_DEL_MULTI: Index: sys/netinet/ip_divert.c =================================================================== --- sys/netinet/ip_divert.c +++ sys/netinet/ip_divert.c @@ -234,7 +234,6 @@ /* Find IP address for receive interface */ ifp = m->m_pkthdr.rcvif; - if_addr_rlock(ifp); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET) continue; @@ -242,7 +241,6 @@ ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr; break; } - if_addr_runlock(ifp); } /* * Record the incoming interface name whenever we have one. Index: sys/netpfil/ipfw/ip_fw2.c =================================================================== --- sys/netpfil/ipfw/ip_fw2.c +++ sys/netpfil/ipfw/ip_fw2.c @@ -406,19 +406,21 @@ } } else { #if !defined(USERSPACE) && defined(__FreeBSD__) /* and OSX too ? */ + struct epoch_tracker et; struct ifaddr *ia; - if_addr_rlock(ifp); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ia, &ifp->if_addrhead, ifa_link) { if (ia->ifa_addr->sa_family != AF_INET) continue; if (cmd->p.ip.s_addr == ((struct sockaddr_in *) (ia->ifa_addr))->sin_addr.s_addr) { - if_addr_runlock(ifp); - return(1); /* match */ + NET_EPOCH_EXIT(et); + + return (1); /* match */ } } - if_addr_runlock(ifp); + NET_EPOCH_EXIT(et); #endif /* __FreeBSD__ */ } return(0); /* no match, fail ... */ Index: sys/netpfil/ipfw/ip_fw_nat.c =================================================================== --- sys/netpfil/ipfw/ip_fw_nat.c +++ sys/netpfil/ipfw/ip_fw_nat.c @@ -114,10 +114,12 @@ IPFW_UH_WLOCK(chain); /* Check every nat entry... */ LIST_FOREACH(ptr, &chain->nat, _next) { + struct epoch_tracker et; + /* ...using nic 'ifp->if_xname' as dynamic alias address. */ if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0) continue; - if_addr_rlock(ifp); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr == NULL) continue; @@ -129,7 +131,7 @@ LibAliasSetAddress(ptr->lib, ptr->ip); IPFW_WUNLOCK(chain); } - if_addr_runlock(ifp); + NET_EPOCH_EXIT(et); } IPFW_UH_WUNLOCK(chain); } Index: sys/netpfil/ipfw/nptv6/nptv6.c =================================================================== --- sys/netpfil/ipfw/nptv6/nptv6.c +++ sys/netpfil/ipfw/nptv6/nptv6.c @@ -534,6 +534,7 @@ nptv6_find_prefix(struct ip_fw_chain *ch, struct nptv6_cfg *cfg, struct ifnet *ifp) { + struct epoch_tracker et; struct ifaddr *ifa; struct in6_ifaddr *ia; @@ -545,7 +546,7 @@ if (ifp == NULL) return; } - if_addr_rlock(ifp); + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -558,7 +559,7 @@ nptv6_set_external(cfg, &ia->ia_addr.sin6_addr); break; } - if_addr_runlock(ifp); + NET_EPOCH_EXIT(et); if_rele(ifp); } Index: sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_multicast.c =================================================================== --- sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -734,92 +734,102 @@ ipoib_mcast_restart(priv); } -void ipoib_mcast_restart(struct ipoib_dev_priv *priv) +struct ipoib_mcast_ctx { + struct ipoib_dev_priv *priv; + struct list_head remove_list; +}; + +static u_int +ipoib_process_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) { - struct ifnet *dev = priv->dev; - struct ifmultiaddr *ifma; - struct ipoib_mcast *mcast, *tmcast; - LIST_HEAD(remove_list); + struct ipoib_mcast_ctx *ctx = arg; + struct ipoib_dev_priv *priv = ctx->priv; + struct ipoib_mcast *mcast; struct ib_sa_mcmember_rec rec; + union ib_gid mgid; + uint8_t *addr; int addrlen; - ipoib_dbg_mcast(priv, "restarting multicast task flags 0x%lX\n", - priv->flags); + addr = LLADDR(sdl); + addrlen = sdl->sdl_alen; + if (!ipoib_mcast_addr_is_valid(addr, addrlen, + priv->dev->if_broadcastaddr)) + return (0); - ipoib_mcast_stop_thread(priv, 0); + memcpy(mgid.raw, addr + 4, sizeof mgid); - if_maddr_rlock(dev); - spin_lock(&priv->lock); + mcast = __ipoib_mcast_find(priv, &mgid); + if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { + struct ipoib_mcast *nmcast; - /* - * Unfortunately, the networking core only gives us a list of all of - * the multicast hardware addresses. We need to figure out which ones - * are new and which ones have been removed - */ + /* ignore group which is directly joined by userspace */ + if (test_bit(IPOIB_FLAG_UMCAST, &priv->flags) && + !ib_sa_get_mcmember_rec(priv->ca, priv->port, &mgid, &rec)) { + ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid %16D\n", + mgid.raw, ":"); + return (0); + } - /* Clear out the found flag */ - list_for_each_entry(mcast, &priv->multicast_list, list) - clear_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags); + /* Not found or send-only group, let's add a new entry */ + ipoib_dbg_mcast(priv, "adding multicast entry for mgid %16D\n", + mgid.raw, ":"); - /* Mark all of the entries that are found or don't exist */ + nmcast = ipoib_mcast_alloc(priv, 0); + if (!nmcast) { + ipoib_warn(priv, "unable to allocate memory for multicast structure\n"); + return (0); + } + set_bit(IPOIB_MCAST_FLAG_FOUND, &nmcast->flags); - CK_STAILQ_FOREACH(ifma, &dev->if_multiaddrs, ifma_link) { - union ib_gid mgid; - uint8_t *addr; + nmcast->mcmember.mgid = mgid; - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - addr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); - addrlen = ((struct sockaddr_dl *)ifma->ifma_addr)->sdl_alen; - if (!ipoib_mcast_addr_is_valid(addr, addrlen, - dev->if_broadcastaddr)) - continue; + if (mcast) { + /* Destroy the send only entry */ + list_move_tail(&mcast->list, &ctx->remove_list); - memcpy(mgid.raw, addr + 4, sizeof mgid); + rb_replace_node(&mcast->rb_node, + &nmcast->rb_node, + &priv->multicast_tree); + } else + __ipoib_mcast_add(priv, nmcast); - mcast = __ipoib_mcast_find(priv, &mgid); - if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { - struct ipoib_mcast *nmcast; + list_add_tail(&nmcast->list, &priv->multicast_list); + } - /* ignore group which is directly joined by userspace */ - if (test_bit(IPOIB_FLAG_UMCAST, &priv->flags) && - !ib_sa_get_mcmember_rec(priv->ca, priv->port, &mgid, &rec)) { - ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid %16D\n", - mgid.raw, ":"); - continue; - } + if (mcast) + set_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags); - /* Not found or send-only group, let's add a new entry */ - ipoib_dbg_mcast(priv, "adding multicast entry for mgid %16D\n", - mgid.raw, ":"); + return (1); +} - nmcast = ipoib_mcast_alloc(priv, 0); - if (!nmcast) { - ipoib_warn(priv, "unable to allocate memory for multicast structure\n"); - continue; - } +void ipoib_mcast_restart(struct ipoib_dev_priv *priv) +{ + struct ipoib_mcast_ctx ctx = { priv, + { &ctx.remove_list, &ctx.remove_list }}; + struct ifnet *dev = priv->dev; + struct ipoib_mcast *mcast, *tmcast; - set_bit(IPOIB_MCAST_FLAG_FOUND, &nmcast->flags); + ipoib_dbg_mcast(priv, "restarting multicast task flags 0x%lX\n", + priv->flags); - nmcast->mcmember.mgid = mgid; + ipoib_mcast_stop_thread(priv, 0); - if (mcast) { - /* Destroy the send only entry */ - list_move_tail(&mcast->list, &remove_list); + spin_lock(&priv->lock); - rb_replace_node(&mcast->rb_node, - &nmcast->rb_node, - &priv->multicast_tree); - } else - __ipoib_mcast_add(priv, nmcast); + /* + * Unfortunately, the networking core only gives us a list of all of + * the multicast hardware addresses. We need to figure out which ones + * are new and which ones have been removed + */ - list_add_tail(&nmcast->list, &priv->multicast_list); - } + /* Clear out the found flag */ + list_for_each_entry(mcast, &priv->multicast_list, list) + clear_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags); - if (mcast) - set_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags); - } + /* Mark all of the entries that are found or don't exist */ + ctx.priv = priv; + if_foreach_llmaddr(dev, ipoib_process_maddr, &ctx); /* Remove all of the entries don't exist anymore */ list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) { @@ -831,15 +841,14 @@ rb_erase(&mcast->rb_node, &priv->multicast_tree); /* Move to the remove list */ - list_move_tail(&mcast->list, &remove_list); + list_move_tail(&mcast->list, &ctx.remove_list); } } spin_unlock(&priv->lock); - if_maddr_runlock(dev); /* We have to cancel outside of the spinlock */ - list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { + list_for_each_entry_safe(mcast, tmcast, &ctx.remove_list, list) { ipoib_mcast_leave(mcast->priv, mcast); ipoib_mcast_free(mcast); } Index: sys/powerpc/ps3/if_glc.c =================================================================== --- sys/powerpc/ps3/if_glc.c +++ sys/powerpc/ps3/if_glc.c @@ -504,12 +504,31 @@ return (err); } +static u_int +glc_add_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct glc_softc *sc = arg; + uint64_t addr; + + /* + * Filter can only hold 32 addresses, so fall back to + * the IFF_ALLMULTI case if we have too many. +1 is for + * broadcast. + */ + if (cnt + 1 == 32) + return (0); + + addr = 0; + memcpy(&((uint8_t *)(&addr))[2], LLADDR(sdl), ETHER_ADDR_LEN); + lv1_net_add_multicast_address(sc->sc_bus, sc->sc_dev, addr, 0); + + return (1); +} + static void glc_set_multicast(struct glc_softc *sc) { struct ifnet *ifp = sc->sc_ifp; - struct ifmultiaddr *inm; - uint64_t addr; int naddrs; /* Clear multicast filter */ @@ -522,30 +541,10 @@ if ((ifp->if_flags & IFF_ALLMULTI) != 0) { lv1_net_add_multicast_address(sc->sc_bus, sc->sc_dev, 0, 1); } else { - if_maddr_rlock(ifp); - naddrs = 1; /* Include broadcast */ - CK_STAILQ_FOREACH(inm, &ifp->if_multiaddrs, ifma_link) { - if (inm->ifma_addr->sa_family != AF_LINK) - continue; - addr = 0; - memcpy(&((uint8_t *)(&addr))[2], - LLADDR((struct sockaddr_dl *)inm->ifma_addr), - ETHER_ADDR_LEN); - - lv1_net_add_multicast_address(sc->sc_bus, sc->sc_dev, - addr, 0); - - /* - * Filter can only hold 32 addresses, so fall back to - * the IFF_ALLMULTI case if we have too many. - */ - if (++naddrs >= 32) { - lv1_net_add_multicast_address(sc->sc_bus, - sc->sc_dev, 0, 1); - break; - } - } - if_maddr_runlock(ifp); + naddrs = if_foreach_llmaddr(ifp, glc_add_maddr, sc); + if (naddrs + 1 == 32) + lv1_net_add_multicast_address(sc->sc_bus, + sc->sc_dev, 0, 1); } } Index: sys/powerpc/pseries/phyp_llan.c =================================================================== --- sys/powerpc/pseries/phyp_llan.c +++ sys/powerpc/pseries/phyp_llan.c @@ -508,28 +508,28 @@ mtx_unlock(&sc->io_lock); } +static u_int +llan_set_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct llan_softc *sc = arg; + uint64_t macaddr = 0; + + memcpy((uint8_t *)&macaddr + 2, LLADDR(sdl), 6); + phyp_hcall(H_MULTICAST_CTRL, sc->unit, LLAN_ADD_MULTICAST, macaddr); + + return (1); +} + static int llan_set_multicast(struct llan_softc *sc) { struct ifnet *ifp = sc->ifp; - struct ifmultiaddr *inm; - uint64_t macaddr = 0; mtx_assert(&sc->io_lock, MA_OWNED); phyp_hcall(H_MULTICAST_CTRL, sc->unit, LLAN_CLEAR_MULTICAST, 0); - if_maddr_rlock(ifp); - CK_STAILQ_FOREACH(inm, &ifp->if_multiaddrs, ifma_link) { - if (inm->ifma_addr->sa_family != AF_LINK) - continue; - - memcpy((uint8_t *)&macaddr + 2, - LLADDR((struct sockaddr_dl *)inm->ifma_addr), 6); - phyp_hcall(H_MULTICAST_CTRL, sc->unit, LLAN_ADD_MULTICAST, - macaddr); - } - if_maddr_runlock(ifp); + if_foreach_llmaddr(ifp, llan_set_maddr, sc); return (0); } Index: sys/sys/epoch.h =================================================================== --- sys/sys/epoch.h +++ sys/sys/epoch.h @@ -92,8 +92,5 @@ void epoch_enter(epoch_t epoch); void epoch_exit(epoch_t epoch); -void epoch_thread_init(struct thread *); -void epoch_thread_fini(struct thread *); - #endif /* _KERNEL */ #endif /* _SYS_EPOCH_H_ */ Index: sys/sys/proc.h =================================================================== --- sys/sys/proc.h +++ sys/sys/proc.h @@ -365,7 +365,6 @@ int td_lastcpu; /* (t) Last cpu we were on. */ int td_oncpu; /* (t) Which cpu we are on. */ void *td_lkpi_task; /* LinuxKPI task struct pointer */ - struct epoch_tracker *td_et; /* (k) compat KPI spare tracker */ int td_pmcpend; SLIST_HEAD(, epoch_tracker) td_epochs; };