diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2013-12-02 23:40:42 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2013-12-02 23:40:42 +0000 |
commit | 25f2df9dec63d8c61018a6a2953b5b5ddbf437b6 (patch) | |
tree | 8a99ba3a3a88710bb174d4a143a56a858c89d4fd | |
parent | bdfb561d717098a76f61e0f7ff85e6f6151a89eb (diff) |
Rewrite receive filter handling and ioctl bits. Fixes not being able to
bring the interface out of all multicast mode once a range of multicast
addresses has been found and missing multicast range checking for some
of the dc(4) variants.
Tested with 21143 (represents most of the dc(4) variants and boards) and
ADMtek based adapters. Untested with ASIX and Xircom based adapters.
Putting it in to move forward. I don't expect any issues with the
ASIX/Xircom adapters with the changes as is.
ok naddy@
-rw-r--r-- | sys/dev/ic/dc.c | 256 | ||||
-rw-r--r-- | sys/dev/ic/dcreg.h | 3 |
2 files changed, 111 insertions, 148 deletions
diff --git a/sys/dev/ic/dc.c b/sys/dev/ic/dc.c index d441e2a7b29..32d81e7244f 100644 --- a/sys/dev/ic/dc.c +++ b/sys/dev/ic/dc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dc.c,v 1.128 2013/11/20 08:36:36 mpi Exp $ */ +/* $OpenBSD: dc.c,v 1.129 2013/12/02 23:40:41 brad Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -887,16 +887,14 @@ dc_crc_le(struct dc_softc *sc, caddr_t addr) void dc_setfilt_21143(struct dc_softc *sc) { - struct dc_desc *sframe; - u_int32_t h, *sp; struct arpcom *ac = &sc->sc_arpcom; + struct ifnet *ifp = &sc->sc_arpcom.ac_if; struct ether_multi *enm; struct ether_multistep step; - struct ifnet *ifp; + struct dc_desc *sframe; + u_int32_t h, *sp; int i; - ifp = &sc->sc_arpcom.ac_if; - i = sc->dc_cdata.dc_tx_prod; DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT); sc->dc_cdata.dc_tx_cnt++; @@ -912,32 +910,31 @@ dc_setfilt_21143(struct dc_softc *sc) sc->dc_cdata.dc_tx_chain[i].sd_mbuf = (struct mbuf *)&sc->dc_ldata->dc_sbuf[0]; - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) - DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); - else - DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); + DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ALLMULTI | DC_NETCFG_RX_PROMISC)); + ifp->if_flags &= ~IFF_ALLMULTI; - if (ac->ac_multirangecnt > 0) + if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { ifp->if_flags |= IFF_ALLMULTI; - - if (ifp->if_flags & IFF_ALLMULTI) - DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); - else { - DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); - + if (ifp->if_flags & IFF_PROMISC) + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); + else + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); + } else { ETHER_FIRST_MULTI(step, ac, enm); while (enm != NULL) { h = dc_crc_le(sc, enm->enm_addrlo); + sp[h >> 4] |= htole32(1 << (h & 0xF)); + ETHER_NEXT_MULTI(step, enm); } } - if (ifp->if_flags & IFF_BROADCAST) { - h = dc_crc_le(sc, (caddr_t)ðerbroadcastaddr); - sp[h >> 4] |= htole32(1 << (h & 0xF)); - } + /* + * Always accept broadcast frames. + */ + h = dc_crc_le(sc, (caddr_t)ðerbroadcastaddr); + sp[h >> 4] |= htole32(1 << (h & 0xF)); /* Set our MAC address */ sp[39] = DC_SP_FIELD(sc->sc_arpcom.ac_enaddr, 0); @@ -972,59 +969,46 @@ dc_setfilt_21143(struct dc_softc *sc) void dc_setfilt_admtek(struct dc_softc *sc) { - struct ifnet *ifp; struct arpcom *ac = &sc->sc_arpcom; + struct ifnet *ifp = &sc->sc_arpcom.ac_if; struct ether_multi *enm; struct ether_multistep step; + u_int32_t hashes[2]; int h = 0; - u_int32_t hashes[2] = { 0, 0 }; - - ifp = &sc->sc_arpcom.ac_if; - - /* Init our MAC address */ - CSR_WRITE_4(sc, DC_AL_PAR0, ac->ac_enaddr[3] << 24 | - ac->ac_enaddr[2] << 16 | ac->ac_enaddr[1] << 8 | ac->ac_enaddr[0]); - CSR_WRITE_4(sc, DC_AL_PAR1, ac->ac_enaddr[5] << 8 | ac->ac_enaddr[4]); - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) - DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); - else - DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); + DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ALLMULTI | DC_NETCFG_RX_PROMISC)); + bzero(hashes, sizeof(hashes)); + ifp->if_flags &= ~IFF_ALLMULTI; - if (ac->ac_multirangecnt > 0) + if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { ifp->if_flags |= IFF_ALLMULTI; + if (ifp->if_flags & IFF_PROMISC) + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); + else + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); + } else { + /* now program new ones */ + ETHER_FIRST_MULTI(step, ac, enm); + while (enm != NULL) { + if (DC_IS_CENTAUR(sc)) + h = dc_crc_le(sc, enm->enm_addrlo); + else + h = dc_crc_be(enm->enm_addrlo); - if (ifp->if_flags & IFF_ALLMULTI) - DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); - else - DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); - - /* first, zot all the existing hash bits */ - CSR_WRITE_4(sc, DC_AL_MAR0, 0); - CSR_WRITE_4(sc, DC_AL_MAR1, 0); - - /* - * If we're already in promisc or allmulti mode, we - * don't have to bother programming the multicast filter. - */ - if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) - return; + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); - /* now program new ones */ - ETHER_FIRST_MULTI(step, ac, enm); - while (enm != NULL) { - if (DC_IS_CENTAUR(sc)) - h = dc_crc_le(sc, enm->enm_addrlo); - else - h = dc_crc_be(enm->enm_addrlo); - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - ETHER_NEXT_MULTI(step, enm); + ETHER_NEXT_MULTI(step, enm); + } } + /* Init our MAC address */ + CSR_WRITE_4(sc, DC_AL_PAR0, ac->ac_enaddr[3] << 24 | + ac->ac_enaddr[2] << 16 | ac->ac_enaddr[1] << 8 | ac->ac_enaddr[0]); + CSR_WRITE_4(sc, DC_AL_PAR1, ac->ac_enaddr[5] << 8 | ac->ac_enaddr[4]); + CSR_WRITE_4(sc, DC_AL_MAR0, hashes[0]); CSR_WRITE_4(sc, DC_AL_MAR1, hashes[1]); } @@ -1032,14 +1016,43 @@ dc_setfilt_admtek(struct dc_softc *sc) void dc_setfilt_asix(struct dc_softc *sc) { - struct ifnet *ifp; struct arpcom *ac = &sc->sc_arpcom; + struct ifnet *ifp = &sc->sc_arpcom.ac_if; struct ether_multi *enm; struct ether_multistep step; + u_int32_t hashes[2]; int h = 0; - u_int32_t hashes[2] = { 0, 0 }; - ifp = &sc->sc_arpcom.ac_if; + DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ALLMULTI | DC_AX_NETCFG_RX_BROAD | + DC_NETCFG_RX_PROMISC)); + bzero(hashes, sizeof(hashes)); + ifp->if_flags &= ~IFF_ALLMULTI; + + /* + * Always accept broadcast frames. + */ + DC_SETBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD); + + if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { + ifp->if_flags |= IFF_ALLMULTI; + if (ifp->if_flags & IFF_PROMISC) + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); + else + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); + } else { + /* now program new ones */ + ETHER_FIRST_MULTI(step, ac, enm); + while (enm != NULL) { + h = dc_crc_be(enm->enm_addrlo); + + if (h < 32) + hashes[0] |= (1 << h); + else + hashes[1] |= (1 << (h - 32)); + + ETHER_NEXT_MULTI(step, enm); + } + } /* Init our MAC address */ CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_PAR0); @@ -1049,50 +1062,6 @@ dc_setfilt_asix(struct dc_softc *sc) CSR_WRITE_4(sc, DC_AX_FILTDATA, *(u_int32_t *)(&sc->sc_arpcom.ac_enaddr[4])); - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) - DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); - else - DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); - - if (ifp->if_flags & IFF_ALLMULTI) - DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); - else - DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); - - /* - * The ASIX chip has a special bit to enable reception - * of broadcast frames. - */ - if (ifp->if_flags & IFF_BROADCAST) - DC_SETBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD); - else - DC_CLRBIT(sc, DC_NETCFG, DC_AX_NETCFG_RX_BROAD); - - /* first, zot all the existing hash bits */ - CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0); - CSR_WRITE_4(sc, DC_AX_FILTDATA, 0); - CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR1); - CSR_WRITE_4(sc, DC_AX_FILTDATA, 0); - - /* - * If we're already in promisc or allmulti mode, we - * don't have to bother programming the multicast filter. - */ - if (ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) - return; - - /* now program new ones */ - ETHER_FIRST_MULTI(step, ac, enm); - while (enm != NULL) { - h = dc_crc_be(enm->enm_addrlo); - if (h < 32) - hashes[0] |= (1 << h); - else - hashes[1] |= (1 << (h - 32)); - ETHER_NEXT_MULTI(step, enm); - } - CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR0); CSR_WRITE_4(sc, DC_AX_FILTDATA, hashes[0]); CSR_WRITE_4(sc, DC_AX_FILTIDX, DC_AX_FILTIDX_MAR1); @@ -1102,15 +1071,14 @@ dc_setfilt_asix(struct dc_softc *sc) void dc_setfilt_xircom(struct dc_softc *sc) { - struct dc_desc *sframe; struct arpcom *ac = &sc->sc_arpcom; + struct ifnet *ifp = &sc->sc_arpcom.ac_if; struct ether_multi *enm; struct ether_multistep step; + struct dc_desc *sframe; u_int32_t h, *sp; - struct ifnet *ifp; int i; - ifp = &sc->sc_arpcom.ac_if; DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON|DC_NETCFG_RX_ON)); i = sc->dc_cdata.dc_tx_prod; @@ -1128,30 +1096,33 @@ dc_setfilt_xircom(struct dc_softc *sc) sc->dc_cdata.dc_tx_chain[i].sd_mbuf = (struct mbuf *)&sc->dc_ldata->dc_sbuf[0]; - /* If we want promiscuous mode, set the allframes bit. */ - if (ifp->if_flags & IFF_PROMISC) - DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); - else - DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); + DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ALLMULTI | DC_NETCFG_RX_PROMISC)); + ifp->if_flags &= ~IFF_ALLMULTI; - if (ifp->if_flags & IFF_ALLMULTI) - DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); - else - DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); + if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { + ifp->if_flags |= IFF_ALLMULTI; + if (ifp->if_flags & IFF_PROMISC) + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); + else + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); + } else { + /* now program new ones */ + ETHER_FIRST_MULTI(step, ac, enm); + while (enm != NULL) { + h = dc_crc_le(sc, enm->enm_addrlo); - /* now program new ones */ - ETHER_FIRST_MULTI(step, ac, enm); - while (enm != NULL) { - h = dc_crc_le(sc, enm->enm_addrlo); - sp[h >> 4] |= htole32(1 << (h & 0xF)); - ETHER_NEXT_MULTI(step, enm); - } + sp[h >> 4] |= htole32(1 << (h & 0xF)); - if (ifp->if_flags & IFF_BROADCAST) { - h = dc_crc_le(sc, (caddr_t)ðerbroadcastaddr); - sp[h >> 4] |= htole32(1 << (h & 0xF)); + ETHER_NEXT_MULTI(step, enm); + } } + /* + * Always accept broadcast frames. + */ + h = dc_crc_le(sc, (caddr_t)ðerbroadcastaddr); + sp[h >> 4] |= htole32(1 << (h & 0xF)); + /* Set our MAC address */ sp[0] = DC_SP_FIELD(sc->sc_arpcom.ac_enaddr, 0); sp[1] = DC_SP_FIELD(sc->sc_arpcom.ac_enaddr, 1); @@ -2964,7 +2935,6 @@ dc_ioctl(struct ifnet *ifp, u_long command, caddr_t data) struct dc_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; struct ifaddr *ifa = (struct ifaddr *)data; - struct mii_data *mii; int s, error = 0; s = splnet(); @@ -2981,26 +2951,20 @@ dc_ioctl(struct ifnet *ifp, u_long command, caddr_t data) break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { - if (ifp->if_flags & IFF_RUNNING && - (ifp->if_flags ^ sc->dc_if_flags) & - IFF_PROMISC) { - dc_setfilt(sc); - } else { - if (!(ifp->if_flags & IFF_RUNNING)) { - sc->dc_txthresh = 0; - dc_init(sc); - } + if (ifp->if_flags & IFF_RUNNING) + error = ENETRESET; + else { + sc->dc_txthresh = 0; + dc_init(sc); } } else { if (ifp->if_flags & IFF_RUNNING) dc_stop(sc, 0); } - sc->dc_if_flags = ifp->if_flags; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: - mii = &sc->sc_mii; - error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); + error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command); #ifdef SRM_MEDIA if (sc->dc_srm_media) sc->dc_srm_media = 0; diff --git a/sys/dev/ic/dcreg.h b/sys/dev/ic/dcreg.h index b2b999a2580..7c592463478 100644 --- a/sys/dev/ic/dcreg.h +++ b/sys/dev/ic/dcreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dcreg.h,v 1.48 2010/09/07 16:21:42 deraadt Exp $ */ +/* $OpenBSD: dcreg.h,v 1.49 2013/12/02 23:40:41 brad Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -730,7 +730,6 @@ struct dc_softc { int dc_romwidth; int dc_pnic_rx_bug_save; unsigned char *dc_pnic_rx_buf; - int dc_if_flags; int dc_if_media; u_int32_t dc_flags; u_int32_t dc_txthresh; |