Subject: Lance Rev C ethernet bug
To: None <gilbertd@cs.man.ac.uk>
From: Gordon W. Ross <gwr@mc.com>
List: port-sun3
Date: 10/26/1995 15:33:51
> Date: Thu, 26 Oct 95 15:55:33 GMT
> From: David Alan Gilbert <gilbertd@cs.man.ac.uk>
>
> Hi All,
> I've just put NetBSD on a (discless) 3/60 here - all seems fine in normal
> use. Its booting off a Sun 4 running SunOS 4.1.3; its running the Generic
> kernel (not the discless one) because we need /dev/bpf...
>
> Now I'm trying to run 'rbootd' to boot an HP 9000/340 into NetBSD; it has
> to do some fairly low level stuff using /dev/bpf. When I start 'rbootd'
> up we get hundreds of warnings in the log about 'le0: Lance revision C
> ehternet bug' and seems to indicate it lost a packet. Anyway, rbootd isn't
> working (the HP doesn't see our system as providing a system for it).
>
> Any advice etc.?
>
> Thanks in advance,
> Dave
Yeah, I blew the code that works around the LANCE Rev. C bug.
Here is a patch you can try:
*** if_le.c.~12~ Wed Jun 28 03:11:11 1995
--- if_le.c Thu Oct 26 15:28:21 1995
***************
*** 631,637 ****
#endif
leread(sc, sc->sc_rbuf + (BUFSIZE * rmd),
(int)cdm->mcnt);
- sc->sc_if.if_ipackets++;
}
cdm->bcnt = -BUFSIZE;
--- 631,636 ----
***************
*** 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 *);
--- 660,684 ----
struct mbuf *m;
struct ether_header *eh;
! ifp = &sc->sc_if;
! if (len <= sizeof(struct ether_header) ||
! len > ETHERMTU + sizeof(struct ether_header)) {
! 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 ****
--- 688,716 ----
* 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 */
+ #ifdef 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);
}
--- 718,734 ----
*/
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);
}