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);
  }