Subject: Lance Rev C ether bug
To: None <D.K.Brownlee@city.ac.uk, gilbertd@cs.man.ac.uk>
From: Gordon W. Ross <gwr@mc.com>
List: port-sun3
Date: 10/27/1995 10:51:32
> Date: Thu, 26 Oct 1995 21:38:18 +0000 (GMT)
> From: David Brownlee <D.K.Brownlee@city.ac.uk>
>
> If -current as of yesterday is ok...
>
> I've put a GENERIC kernel up with the LANCE_REVC_BUG undef'd on
> ftp://ftp.city.ac.uk/incoming/netbsd/netbsd_sun3_lance.gz
OK, but be warned this bug can cause NFS file corruption.
I recommend the patch below instead. (This one works! 8^)
> (I'd just compiled up a normal generic kernel and made a binary
> snapshot from yesterdays sup for my own use :)
Thanks. I'm still waiting for access to the NetBSD FTP server...
> While I'm at it I'll put yesterdays snapshot there as well if you
> want the entire system!
>
> David/abs
>
> david@city.ac.uk +44 171 477 8186 (MIME) david@southern.com +44 0181 88 8949
> Network Analyst, UCS, City University System Manager, Southern Studios Ltd
> Northampton Square, London EC1V 0HB PO Box 59, London N22 1AR
Here is a patch for the "le" driver.
This one has been tested too!
(Sorry about the previous two...)
Gordon Ross
*** if_le.c.~12~ Wed Jun 28 03:11:11 1995
--- if_le.c Thu Oct 26 23:01:17 1995
***************
*** 51,58 ****
#include <machine/autoconf.h>
#include <machine/cpu.h>
! /* XXX - Yes, we DO have to deal with this bug. */
#define LANCE_REVC_BUG 1
/* #define LEDEBUG 1 */
--- 51,67 ----
#include <machine/autoconf.h>
#include <machine/cpu.h>
! /*
! * XXX - Be warned: Most Sun3/50 and many Sun3/60 machines have
! * the LANCE Rev. C bug, which we MUST avoid or suffer likely
! * NFS file corruption and worse! That said, if you are SURE
! * your LANCE is OK, you can remove this work-around using:
! * options LANCE_REVC_BUG=0
! * in your kernel config file.
! */
! #ifndef LANCE_REVC_BUG
#define LANCE_REVC_BUG 1
+ #endif
/* #define LEDEBUG 1 */
***************
*** 168,175 ****
ifp->if_watchdog = lewatchdog;
ifp->if_flags =
IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
! #ifndef LANCE_REVC_BUG
! /* XXX - Must be a better way... */
ifp->if_flags |= IFF_MULTICAST;
#endif
--- 177,185 ----
ifp->if_watchdog = lewatchdog;
ifp->if_flags =
IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
!
! #if LANCE_REVC_BUG == 0
! /* The work-around precludes multicast... */
ifp->if_flags |= IFF_MULTICAST;
#endif
***************
*** 176,181 ****
--- 186,192 ----
/* Attach the interface. */
if_attach(ifp);
ether_ifattach(ifp);
+
#if NBPFILTER > 0
bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
#endif
***************
*** 631,637 ****
#endif
leread(sc, sc->sc_rbuf + (BUFSIZE * rmd),
(int)cdm->mcnt);
- sc->sc_if.if_ipackets++;
}
cdm->bcnt = -BUFSIZE;
--- 642,647 ----
***************
*** 661,703 ****
struct mbuf *m;
struct ether_header *eh;
! len -= 4;
! if (len <= 0)
! return;
! #ifdef LANCE_REVC_BUG /* XXX - Must be a better way... */
! /*
! * Check for unreported packet errors. Rev C of the LANCE chip
! * has a bug which can cause "random" bytes to be prepended to
! * the start of the packet. The work-around is to make sure that
! * the Ethernet destination address in the packet matches our
! * address (or the broadcast address).
! */
! {
! register short *pp, *ea;
!
! pp = (short *) buf;
! ea = (short *) &sc->sc_enaddr;
! if ((pp[0] == ea[0]) && (pp[1] == ea[1]) && (pp[2] == ea[2]))
! goto ok;
! if ((pp[0] == -1) && (pp[1] == -1) && (pp[2] == -1))
! goto ok;
! /* XXX - Multicast packets? */
!
! sc->sc_if.if_ierrors++;
! log(LOG_ERR, "%s: LANCE Rev C Extra Byte(s) bug; Packet punted\n",
! sc->sc_dev.dv_xname);
return;
- ok:
}
- #endif /* LANCE_REVC_BUG */
/* Pull packet off interface. */
- ifp = &sc->sc_if;
m = leget(buf, len, ifp);
! if (m == 0)
return;
/* We assume that the header fit entirely in one mbuf. */
eh = mtod(m, struct ether_header *);
--- 671,694 ----
struct mbuf *m;
struct ether_header *eh;
! ifp = &sc->sc_if;
! if ((len < ETHERMIN) || (len > ETHER_MAX_LEN)) {
! printf("%s: invalid packet size %d; dropping\n",
! sc->sc_dev.dv_xname, len);
! ifp->if_ierrors++;
return;
}
/* Pull packet off interface. */
m = leget(buf, len, ifp);
! if (m == 0) {
! ifp->if_ierrors++;
return;
+ }
+ ifp->if_ipackets++;
+
/* We assume that the header fit entirely in one mbuf. */
eh = mtod(m, struct ether_header *);
***************
*** 707,714 ****
--- 698,726 ----
* If so, hand off the raw packet to BPF.
*/
if (ifp->if_bpf) {
+ /* Note that BPF may see garbage! (LANCE_REVC_BUG) */
bpf_mtap(ifp->if_bpf, m);
+ }
+ #endif /* NBPFILTER */
+ #if LANCE_REVC_BUG
+ /*
+ * Check for unreported packet errors. Rev C of the LANCE chip
+ * has a bug which can cause "random" bytes to be prepended to
+ * the start of the packet. The work-around is to make sure that
+ * the Ethernet destination address in the packet matches our
+ * address (or the broadcast address). Must ALWAYS check!
+ */
+ if (bcmp(eh->ether_dhost, sc->sc_enaddr, 6) &&
+ bcmp(eh->ether_dhost, etherbroadcastaddr, 6))
+ {
+ /* Not for us. */
+ m_freem(m);
+ return;
+ }
+ #else /* LANCE_REVC_BUG */
+ #if NBPFILTER > 0
+ if (ifp->if_bpf) {
/*
* Note that the interface cannot be in promiscuous mode if
* there are no BPF listeners. And if we are in promiscuous
***************
*** 716,734 ****
*/
if ((ifp->if_flags & IFF_PROMISC) &&
(eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
! bcmp(eh->ether_dhost, sc->sc_enaddr,
! sizeof(eh->ether_dhost)) != 0) {
m_freem(m);
return;
}
}
! #endif
! /* We assume that the header fit entirely in one mbuf. */
! m->m_pkthdr.len -= sizeof(*eh);
! m->m_len -= sizeof(*eh);
! m->m_data += sizeof(*eh);
!
ether_input(ifp, eh, m);
}
--- 728,744 ----
*/
if ((ifp->if_flags & IFF_PROMISC) &&
(eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
! bcmp(eh->ether_dhost, sc->sc_enaddr, 6) != 0)
! {
m_freem(m);
return;
}
}
! #endif /* NBPFILTER */
! #endif /* LANCE_REVC_BUG */
! /* Pass the packet up, with the ether header sort-of removed. */
! m_adj(m, sizeof(struct ether_header));
ether_input(ifp, eh, m);
}