More multicast stuff

>From cmaeda@cs.washington.edu
These patches are derived from the IP Multicast patches for BSDI.
This commit is contained in:
hpeyerl 1993-12-10 05:37:33 +00:00
parent a09abb4d2b
commit dc1b697fb8
2 changed files with 268 additions and 80 deletions

View File

@ -20,7 +20,7 @@
*/
/*
* $Id: if_ed.c,v 1.10 1993/10/23 04:59:41 davidg Exp $
* $Id: if_ed.c,v 1.11 1993/12/10 05:37:33 hpeyerl Exp $
*/
/*
@ -174,6 +174,7 @@ struct ed_softc {
int ed_attach(), ed_init(), edintr(), ed_ioctl(), ed_probe(),
ed_start(), ed_reset(), ed_watchdog();
void ds_getmcaf();
static void ed_stop();
@ -994,6 +995,9 @@ ed_attach(isa_dev)
| IFF_ALTPHYS);
else
ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
#ifdef MULTICAST
ifp->if_flags |= IFF_MULTICAST;
#endif
/*
* Attach the interface
@ -1165,10 +1169,16 @@ ed_init(unit)
outb(sc->nic_addr + ED_P0_RBCR0, 0);
outb(sc->nic_addr + ED_P0_RBCR1, 0);
#if 0
/*
* Enable reception of broadcast packets
*/
outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
#endif
/*
* Tell RCR to do nothing for now.
*/
outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON);
/*
* Place NIC in internal loopback mode
@ -1213,15 +1223,24 @@ ed_init(unit)
for (i = 0; i < ETHER_ADDR_LEN; ++i)
outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]);
#if NBPFILTER > 0
/*
* Initialize multicast address hashing registers to accept
* all multicasts (only used when in promiscuous mode)
*/
for (i = 0; i < 8; ++i)
outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff);
#endif
#ifdef MULTICAST
/* set up multicast addresses and filter modes */
if (sc != 0 && (ifp->if_flags & IFF_MULTICAST) != 0) {
u_long mcaf[2];
if ((ifp->if_flags & IFF_ALLMULTI) != 0) {
mcaf[0] = 0xffffffff;
mcaf[1] = 0xffffffff;
} else
ds_getmcaf(sc, mcaf);
/*
* Set multicast filter on chip.
*/
for (i = 0; i < 8; i++)
outb(sc->nic_addr + ED_P1_MAR0 + i, ((u_char *)mcaf)[i]);
}
#endif
/*
* Set Current Page pointer to next_packet (initialized above)
*/
@ -1233,6 +1252,11 @@ ed_init(unit)
*/
outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA);
/*
* Clear all interrupts.
*/
outb(sc->nic_addr + ED_P0_ISR, 0xff);
/*
* Take interface out of loopback
*/
@ -1250,6 +1274,25 @@ ed_init(unit)
}
}
i = ED_RCR_AB;
if (sc != 0) {
if ((ifp->if_flags & IFF_PROMISC) != 0) {
/*
* Set promiscuous mode.
* Also reconfigure the multicast filter.
*/
int j;
i |= ED_RCR_PRO|ED_RCR_AM|ED_RCR_AR|ED_RCR_SEP;
for (j = 0; j < 8; j++)
outb(sc->nic_addr + ED_P1_MAR0 + j, 0xff);
}
#ifdef MULTICAST
i |= ED_RCR_AM;
#endif
}
outb(sc->nic_addr + ED_P0_RCR, i);
/*
* Set 'running' flag, and clear output active flag.
*/
@ -1892,41 +1935,32 @@ ed_ioctl(ifp, command, data)
((ifp->if_flags & IFF_RUNNING) == 0))
ed_init(ifp->if_unit);
}
#if NBPFILTER > 0
if (ifp->if_flags & IFF_PROMISC) {
/*
* Set promiscuous mode on interface.
* XXX - for multicasts to work, we would need to
* write 1's in all bits of multicast
* hashing array. For now we assume that
* this was done in ed_init().
*/
outb(sc->nic_addr + ED_P0_RCR,
ED_RCR_PRO|ED_RCR_AM|ED_RCR_AB);
} else {
/*
* XXX - for multicasts to work, we would need to
* rewrite the multicast hashing array with the
* proper hash (would have been destroyed above).
*/
outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
}
#endif
/*
* An unfortunate hack to provide the (required) software control
* of the tranceiver for 3Com boards. The ALTPHYS flag disables
* the tranceiver if set.
* NB: There was a bunch of code here that's now in ed_init.
*/
if (sc->vendor == ED_VENDOR_3COM) {
if (ifp->if_flags & IFF_ALTPHYS) {
outb(sc->asic_addr + ED_3COM_CR, 0);
} else {
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
}
}
break;
#ifdef MULTICAST
case SIOCADDMULTI:
case SIOCDELMULTI:
/*
* Update our multicast list.
*/
error = (command == SIOCADDMULTI) ?
ether_addmulti((struct ifreq *)data, &sc->arpcom):
ether_delmulti((struct ifreq *)data, &sc->arpcom);
if (error == ENETRESET) {
/*
* Multicast list has changed; set the hardware filter
* accordingly.
*/
ed_stop(ifp->if_unit); /* XXX for ds_setmcaf? */
ed_init(ifp->if_unit);
error = 0;
}
break;
#endif
default:
error = EINVAL;
}
@ -2372,4 +2406,64 @@ ed_ring_to_mbuf(sc,src,dst,total_len)
}
return (m);
}
#ifdef MULTICAST
/*
* Compute crc for ethernet address
*/
u_long
ds_crc(ep)
u_char *ep;
{
#define POLYNOMIAL 0x04c11db6
register u_long crc = 0xffffffffL;
register int carry, i, j;
register u_char b;
for (i = 6; --i >= 0; ) {
b = *ep++;
for (j = 8; --j >= 0; ) {
carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
crc <<= 1;
b >>= 1;
if (carry)
crc = ((crc ^ POLYNOMIAL) | carry);
}
}
return crc;
#undef POLYNOMIAL
}
/*
* Compute the multicast address filter from the
* list of multicast addresses we need to listen to.
*/
void
ds_getmcaf(sc, mcaf)
struct ed_softc *sc;
u_long *mcaf;
{
register u_int index;
register u_char *af = (u_char*)mcaf;
register struct ether_multi *enm;
register struct ether_multistep step;
mcaf[0] = 0;
mcaf[1] = 0;
ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
while (enm != NULL) {
if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
mcaf[0] = 0xffffffff;
mcaf[1] = 0xffffffff;
return;
}
index = ds_crc(enm->enm_addrlo, 6) >> 26;
af[index >> 3] |= 1 << (index & 7);
ETHER_NEXT_MULTI(step, enm);
}
}
#endif
#endif

View File

@ -20,7 +20,7 @@
*/
/*
* $Id: if_ed.c,v 1.10 1993/10/23 04:59:41 davidg Exp $
* $Id: if_ed.c,v 1.11 1993/12/10 05:37:33 hpeyerl Exp $
*/
/*
@ -174,6 +174,7 @@ struct ed_softc {
int ed_attach(), ed_init(), edintr(), ed_ioctl(), ed_probe(),
ed_start(), ed_reset(), ed_watchdog();
void ds_getmcaf();
static void ed_stop();
@ -994,6 +995,9 @@ ed_attach(isa_dev)
| IFF_ALTPHYS);
else
ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
#ifdef MULTICAST
ifp->if_flags |= IFF_MULTICAST;
#endif
/*
* Attach the interface
@ -1165,10 +1169,16 @@ ed_init(unit)
outb(sc->nic_addr + ED_P0_RBCR0, 0);
outb(sc->nic_addr + ED_P0_RBCR1, 0);
#if 0
/*
* Enable reception of broadcast packets
*/
outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
#endif
/*
* Tell RCR to do nothing for now.
*/
outb(sc->nic_addr + ED_P0_RCR, ED_RCR_MON);
/*
* Place NIC in internal loopback mode
@ -1213,15 +1223,24 @@ ed_init(unit)
for (i = 0; i < ETHER_ADDR_LEN; ++i)
outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]);
#if NBPFILTER > 0
/*
* Initialize multicast address hashing registers to accept
* all multicasts (only used when in promiscuous mode)
*/
for (i = 0; i < 8; ++i)
outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff);
#endif
#ifdef MULTICAST
/* set up multicast addresses and filter modes */
if (sc != 0 && (ifp->if_flags & IFF_MULTICAST) != 0) {
u_long mcaf[2];
if ((ifp->if_flags & IFF_ALLMULTI) != 0) {
mcaf[0] = 0xffffffff;
mcaf[1] = 0xffffffff;
} else
ds_getmcaf(sc, mcaf);
/*
* Set multicast filter on chip.
*/
for (i = 0; i < 8; i++)
outb(sc->nic_addr + ED_P1_MAR0 + i, ((u_char *)mcaf)[i]);
}
#endif
/*
* Set Current Page pointer to next_packet (initialized above)
*/
@ -1233,6 +1252,11 @@ ed_init(unit)
*/
outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA);
/*
* Clear all interrupts.
*/
outb(sc->nic_addr + ED_P0_ISR, 0xff);
/*
* Take interface out of loopback
*/
@ -1250,6 +1274,25 @@ ed_init(unit)
}
}
i = ED_RCR_AB;
if (sc != 0) {
if ((ifp->if_flags & IFF_PROMISC) != 0) {
/*
* Set promiscuous mode.
* Also reconfigure the multicast filter.
*/
int j;
i |= ED_RCR_PRO|ED_RCR_AM|ED_RCR_AR|ED_RCR_SEP;
for (j = 0; j < 8; j++)
outb(sc->nic_addr + ED_P1_MAR0 + j, 0xff);
}
#ifdef MULTICAST
i |= ED_RCR_AM;
#endif
}
outb(sc->nic_addr + ED_P0_RCR, i);
/*
* Set 'running' flag, and clear output active flag.
*/
@ -1892,41 +1935,32 @@ ed_ioctl(ifp, command, data)
((ifp->if_flags & IFF_RUNNING) == 0))
ed_init(ifp->if_unit);
}
#if NBPFILTER > 0
if (ifp->if_flags & IFF_PROMISC) {
/*
* Set promiscuous mode on interface.
* XXX - for multicasts to work, we would need to
* write 1's in all bits of multicast
* hashing array. For now we assume that
* this was done in ed_init().
*/
outb(sc->nic_addr + ED_P0_RCR,
ED_RCR_PRO|ED_RCR_AM|ED_RCR_AB);
} else {
/*
* XXX - for multicasts to work, we would need to
* rewrite the multicast hashing array with the
* proper hash (would have been destroyed above).
*/
outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB);
}
#endif
/*
* An unfortunate hack to provide the (required) software control
* of the tranceiver for 3Com boards. The ALTPHYS flag disables
* the tranceiver if set.
* NB: There was a bunch of code here that's now in ed_init.
*/
if (sc->vendor == ED_VENDOR_3COM) {
if (ifp->if_flags & IFF_ALTPHYS) {
outb(sc->asic_addr + ED_3COM_CR, 0);
} else {
outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL);
}
}
break;
#ifdef MULTICAST
case SIOCADDMULTI:
case SIOCDELMULTI:
/*
* Update our multicast list.
*/
error = (command == SIOCADDMULTI) ?
ether_addmulti((struct ifreq *)data, &sc->arpcom):
ether_delmulti((struct ifreq *)data, &sc->arpcom);
if (error == ENETRESET) {
/*
* Multicast list has changed; set the hardware filter
* accordingly.
*/
ed_stop(ifp->if_unit); /* XXX for ds_setmcaf? */
ed_init(ifp->if_unit);
error = 0;
}
break;
#endif
default:
error = EINVAL;
}
@ -2372,4 +2406,64 @@ ed_ring_to_mbuf(sc,src,dst,total_len)
}
return (m);
}
#ifdef MULTICAST
/*
* Compute crc for ethernet address
*/
u_long
ds_crc(ep)
u_char *ep;
{
#define POLYNOMIAL 0x04c11db6
register u_long crc = 0xffffffffL;
register int carry, i, j;
register u_char b;
for (i = 6; --i >= 0; ) {
b = *ep++;
for (j = 8; --j >= 0; ) {
carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
crc <<= 1;
b >>= 1;
if (carry)
crc = ((crc ^ POLYNOMIAL) | carry);
}
}
return crc;
#undef POLYNOMIAL
}
/*
* Compute the multicast address filter from the
* list of multicast addresses we need to listen to.
*/
void
ds_getmcaf(sc, mcaf)
struct ed_softc *sc;
u_long *mcaf;
{
register u_int index;
register u_char *af = (u_char*)mcaf;
register struct ether_multi *enm;
register struct ether_multistep step;
mcaf[0] = 0;
mcaf[1] = 0;
ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
while (enm != NULL) {
if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
mcaf[0] = 0xffffffff;
mcaf[1] = 0xffffffff;
return;
}
index = ds_crc(enm->enm_addrlo, 6) >> 26;
af[index >> 3] |= 1 << (index & 7);
ETHER_NEXT_MULTI(step, enm);
}
}
#endif
#endif