*BSD News Article 15116


Return to BSD News archive

Newsgroups: comp.os.386bsd.bugs
Path: sserve!newshost.anu.edu.au!munnari.oz.au!hp9000.csc.cuhk.hk!saimiri.primate.wisc.edu!zaphod.mps.ohio-state.edu!cs.utexas.edu!uunet!email!mbirgmei
From: mbirgmei@email.tuwien.ac.at (Martin BIRGMEIER)
Subject: Patches for if_ec.* to work with BPF
Message-ID: <1993Apr26.071622.3817@email.tuwien.ac.at>
Organization: Technical University of Vienna
Date: Mon, 26 Apr 1993 07:16:22 GMT
Lines: 907

Below are the patches I hacked up to get my 3c503 card to work with the
Berkeley Packet Filter. I have been using them for a while now (since
well before pk 0.2 came along) and they seem to be running fine. To
arrive at them, I simply diffed the old and new versions of if_we*, and
manually applied the resulting changes to if_ec.* (these interfaces are
the same for all practical purposes, the chip being the same as I
understood from the comments in if_ec.c). So basically if_ec.* should
now offer all of the functionality of if_we* (I hope :-)).

Enjoy,

Martin

P.S. One more thing - cut out that silly printf() statement in if_ec.c -
this should have made it into the patchkit a long time ago. I let it
follow as my first diff, thereafter the BPF diff stuff.

============================== cut here ==============================
*** /usr/src/sys.386bsd/i386/isa/if_ec.c.ECINIT_ORIG	Sun May 31 00:09:06 1992
--- /usr/src/sys.386bsd/i386/isa/if_ec.c	Tue Jan 26 10:15:44 1993
***************
*** 261,267 ****
  	u_short   ax, cx;
  
  	Bdry=0;
- printf("ecinit");
  /*
   * Address not known.
   */
--- 261,266 ----
============================== cut here ==============================
*** /usr/src/sys.386bsd/i386/isa/if_ec.h.BPF_ORIG	Mon May 25 12:18:40 1992
--- /usr/src/sys.386bsd/i386/isa/if_ec.h	Wed Mar 24 10:12:58 1993
***************
*** 169,177 ****
   */
  #define ENRXCR_MON	0x20	/* Monitor mode (no packets rcvd) */
  #define ENRXCR_PROMP	0x10	/* Promiscuous phys addresses. */
! #define ENRXCR_MULTI	0x8	/* Multicast (if pass filter) */
! #define ENRXCR_BCST	0x4	/* Accept broadcasts */
! #define ENRXCR_BAD	0x3	/* Accept runts and bad CRC frames */
  /*
   * Commands for TX control reg
   */
--- 169,179 ----
   */
  #define ENRXCR_MON	0x20	/* Monitor mode (no packets rcvd) */
  #define ENRXCR_PROMP	0x10	/* Promiscuous phys addresses. */
! #define ENRXCR_MULTI	0x08	/* Multicast (if pass filter) */
! #define ENRXCR_BCST	0x04	/* Accept broadcasts */
! #define ENRXCR_RUNT	0x02	/* Accept runts */
! #define ENRXCR_CRC	0x01	/* Accept bad CRC frames */
! #define ENRXCR_BAD	(ENRXCR_RUNT | ENRXCR_CRC)
  /*
   * Commands for TX control reg
   */
*** /usr/src/sys.386bsd/i386/isa/if_ec.c.BPF_ORIG	Mon Mar 22 15:08:26 1993
--- /usr/src/sys.386bsd/i386/isa/if_ec.c	Wed Mar 24 10:12:57 1993
***************
*** 64,69 ****
--- 64,73 ----
   *   repairs this bit after obtaining it's information since I didn't know
   *   what else within the depths of the kernel would freak out if I left it.
   */
+ /*
+  * BPF filter support added by MB 03/16/93, modeled after the changes
+  * made to if_we.c by Marc Frajola and David Greenman
+  */
  #include "param.h"
  #include "mbuf.h"
  #include "socket.h"
***************
*** 71,76 ****
--- 75,82 ----
  #include "errno.h"
  #include "syslog.h"
  #include "net/if.h"
+ #include "net/if_types.h"
+ #include "net/if_dl.h"
  #include "net/netisr.h"
  #ifdef INET
  #include "netinet/in.h"
***************
*** 85,90 ****
--- 91,103 ----
  #endif
  #include "i386/isa/isa_device.h"
  #include "i386/isa/if_ec.h"
+ #include "bpfilter.h"
+ #if NBPFILTER > 0
+ #include "net/bpf.h"
+ #include "net/bpfdesc.h"
+ #endif /* NBPFILTER > 0 */
+ 
+ static inline caddr_t ec_ring_copy();
  
  /*
   * Ethernet software status per interface.
***************
*** 101,106 ****
--- 114,122 ----
  	u_char	ec_flags;		/* software state		*/
  #define	EC_RUNNING	0x01
  #define EC_TXBUSY	0x02
+ #if NBPFILTER > 0
+ #define EC_ATTACHED	0x80
+ #endif
  
  	u_char	ec_type;		/* interface type code		*/
  	u_short	ec_vector;		/* interrupt vector 		*/
***************
*** 111,122 ****
  	caddr_t	ec_vmem_addr;		/* card RAM virtual memory base */
  	u_long	ec_vmem_size;		/* card RAM bytes		*/
  	caddr_t	ec_vmem_ring;		/* receive ring RAM vaddress	*/
! 	caddr_t	ec_vmem_end;		/* receive ring RAM end	*/
  } ec_softc[NEC];
  
! #define PAGE0  outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0);
! #define PAGE1  outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE1);
! static Bdry;
  
  int ether_output(),
      ecprobe(),
--- 127,141 ----
  	caddr_t	ec_vmem_addr;		/* card RAM virtual memory base */
  	u_long	ec_vmem_size;		/* card RAM bytes		*/
  	caddr_t	ec_vmem_ring;		/* receive ring RAM vaddress	*/
! 	caddr_t	ec_vmem_end;		/* receive ring RAM end		*/
! #if NBPFILTER > 0
! 	caddr_t	ec_bpf;			/* Magic Cookie for BPF		*/
! #endif
  } ec_softc[NEC];
  
! #define PAGE0  { outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0); }
! #define PAGE1  { outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE1); }
! static Bdry[NEC];
  
  int ether_output(),
      ecprobe(),
***************
*** 166,172 ****
   * Stop the chip just in case.
   */
  	DELAY(1000);
! 	PAGE0
  	outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP);
  	DELAY(1000);
  
--- 185,191 ----
   * Stop the chip just in case.
   */
  	DELAY(1000);
! 	PAGE0;
  	outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP);
  	DELAY(1000);
  
***************
*** 198,203 ****
--- 217,224 ----
  {
  	register struct ec_softc *sc = &ec_softc[is->id_unit];
  	register struct ifnet *ifp = &sc->ec_if;
+ 	struct ifaddr *ifa;
+ 	struct sockaddr_dl *sdl;
  
  /**
   ** Initialize the ASIC in same order as Clarkson driver.
***************
*** 247,252 ****
--- 268,293 ----
   */
  	if_attach(ifp);
  /*
+  * Search down the ifa address list looking for the AF_LINK type entry
+  */
+ 	ifa = ifp->if_addrlist;
+ 	while ((ifa != 0) && (ifa->ifa_addr != 0) &&
+ 	 (ifa->ifa_addr->sa_family != AF_LINK))
+ 		ifa = ifa->ifa_next;
+ /*
+  * If we found an AF_LINK type entry, we fill in the hardware (link level) addr
+  */
+ 	if ((ifa != 0) && (ifa->ifa_addr != 0)) {
+ 		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ 		sdl->sdl_type = IFT_ETHER;
+ 		sdl->sdl_alen = ETHER_ADDR_LEN;
+ 		sdl->sdl_slen = 0;
+ 		bcopy(sc->ec_addr, LLADDR(sdl), ETHER_ADDR_LEN);
+ 	}
+ #if NBPFILTER > 0
+ 	sc->ec_flags &= ~EC_ATTACHED;	/* Make sure BPF attach flag clear */
+ #endif
+ /*
   * Weeee.. We get to tell people we exist...
   */
  	printf(" address %s", ether_sprintf(sc->ec_addr));
***************
*** 260,266 ****
  	int i, s;
  	u_short   ax, cx;
  
! 	Bdry=0;
  /*
   * Address not known.
   */
--- 301,316 ----
  	int i, s;
  	u_short   ax, cx;
  
! 	Bdry[unit] = 0;
! 
! #if NBPFILTER > 0
! 	if ((sc->ec_flags & EC_ATTACHED) == 0) {
! 		bpfattach(&sc->ec_bpf, ifp, DLT_EN10MB,
! 		 sizeof(struct ether_header));
! 		sc->ec_flags |= EC_ATTACHED;
! 	}
! #endif /* NBPFILTER > 0 */
! 
  /*
   * Address not known.
   */
***************
*** 281,287 ****
   *   (Use sequence recommended by 3Com. )
   */
  	s=splhigh();
! 	PAGE0
  	outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0|ENC_STOP);
  	outb(sc->ec_io_nic_addr + EN0_DCFG, ENDCFG_BM8);
  	outb(sc->ec_io_nic_addr + EN0_RCNTLO, 0x0);
--- 331,337 ----
   *   (Use sequence recommended by 3Com. )
   */
  	s=splhigh();
! 	PAGE0;
  	outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_PAGE0|ENC_STOP);
  	outb(sc->ec_io_nic_addr + EN0_DCFG, ENDCFG_BM8);
  	outb(sc->ec_io_nic_addr + EN0_RCNTLO, 0x0);
***************
*** 297,303 ****
  /*
   * Copy Ethernet address from SA_PROM into 8390 chip registers.
   */
! 	PAGE1
  	for(i=0;i<6;i++)
  		outb(sc->ec_io_nic_addr + EN1_PHYS+i, sc->ec_addr[i]);
  /*
--- 347,353 ----
  /*
   * Copy Ethernet address from SA_PROM into 8390 chip registers.
   */
! 	PAGE1;
  	for(i=0;i<6;i++)
  		outb(sc->ec_io_nic_addr + EN1_PHYS+i, sc->ec_addr[i]);
  /*
***************
*** 317,322 ****
--- 367,378 ----
  	outb(sc->ec_io_nic_addr + EN_CCMD, ENC_START|ENC_PAGE0|ENC_NODMA);
  	outb(sc->ec_io_nic_addr + EN0_ISR, 0xff);
  	outb(sc->ec_io_nic_addr + EN0_TXCR, 0x0);
+ #if NBPFILTER > 0
+ 	if (sc->ec_if.if_flags & IFF_PROMISC)
+ 		outb(sc->ec_io_nic_addr + EN0_RXCR,
+ 		 ENRXCR_BAD | ENRXCR_PROMP | ENRXCR_BCST);
+ 	else
+ #endif
  	outb(sc->ec_io_nic_addr + EN0_RXCR, ENRXCR_BCST);
  /*
   * Take interface out of reset, program the vector,
***************
*** 357,362 ****
--- 413,481 ----
  	sc->ec_flags |= EC_TXBUSY;
  	(void) splx(s);
  
+ #if NBPFILTER > 0
+ 	if (sc->ec_bpf) {
+ 		u_short etype;
+ 		int off, datasize, resid;
+ 		struct ether_header *eh;
+ 		struct trailer_header {
+ 			u_short ether_type;
+ 			u_short ether_residual;
+ 		} trailer_header;
+ 		char ether_packet[ETHERMTU+100];
+ 		char *ep;
+ 
+ 		ep = ether_packet;
+ 
+ 		/*
+ 		 * We handle trailers below:
+ 		 * Copy ether header first, then residual data,
+ 		 * then data. Put all this in a temporary buffer
+ 		 * 'ether_packet' and send off to bpf. Since the
+ 		 * system has generated this packet, we assume
+ 		 * that all of the offsets in the packet are
+ 		 * correct; if they're not, the system will almost
+ 		 * certainly crash in m_copydata.
+ 		 * We make no assumptions about how the data is
+ 		 * arranged in the mbuf chain (i.e. how much
+ 		 * data is in each mbuf, if mbuf clusters are
+ 		 * used, etc.), which is why we use m_copydata
+ 		 * to get the ether header rather than assume
+ 		 * that this is located in the first mbuf.
+ 		 */
+ 		/* copy ether header */
+ 		m_copydata(m, 0, sizeof(struct ether_header), ep);
+ 		eh = (struct ether_header *) ep;
+ 		ep += sizeof(struct ether_header);
+ 		etype = ntohs(eh->ether_type);
+ 		if (etype >= ETHERTYPE_TRAIL &&
+ 		    etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
+ 			datasize = ((etype - ETHERTYPE_TRAIL) << 9);
+ 			off = datasize + sizeof(struct ether_header);
+ 
+ 			/* copy trailer_header into a data structure */
+ 			m_copydata(m, off, sizeof(struct trailer_header),
+ 				&trailer_header.ether_type);
+ 
+ 			/* copy residual data */
+ 			m_copydata(m, off+sizeof(struct trailer_header),
+ 				resid = ntohs(trailer_header.ether_residual) -
+ 				sizeof(struct trailer_header), ep);
+ 			ep += resid;
+ 
+ 			/* copy data */
+ 			m_copydata(m, sizeof(struct ether_header), datasize, ep);
+ 			ep += datasize;
+ 
+ 			/* restore original ether packet type */
+ 			eh->ether_type = trailer_header.ether_type;
+ 
+ 			bpf_tap(sc->ec_bpf, ether_packet, ep - ether_packet);
+ 		} else
+ 			bpf_mtap(sc->ec_bpf, m);
+ 	}
+ #endif /* NBPFILTER > 0 */
+ 
  /*
   * Copy the mbuf chain into the transmit buffer
   */
***************
*** 375,385 ****
   */
  	s=splhigh();
  	len = MAX(len, ETHER_MIN_LEN);
! 	PAGE0
  	outb(sc->ec_io_nic_addr + EN0_TCNTLO, len & 0xff);
  	outb(sc->ec_io_nic_addr + EN0_TCNTHI, len >> 8);
  	ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD);
  	outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg|ENC_TRANS);
  	(void) splx(s);
  }
  
--- 494,505 ----
   */
  	s=splhigh();
  	len = MAX(len, ETHER_MIN_LEN);
! 	PAGE0;
  	outb(sc->ec_io_nic_addr + EN0_TCNTLO, len & 0xff);
  	outb(sc->ec_io_nic_addr + EN0_TCNTHI, len >> 8);
  	ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD);
  	outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg|ENC_TRANS);
+ 	sc->ec_if.if_timer = 3;
  	(void) splx(s);
  }
  
***************
*** 399,405 ****
   * Turn off interrupts while we take care of things.
   */
  	ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD);
! 	PAGE0
  	ec_sts_reg = inb(sc->ec_io_nic_addr + EN0_ISR);
  	outb(sc->ec_io_nic_addr + EN0_IMR, 0x0);
  loop:
--- 519,525 ----
   * Turn off interrupts while we take care of things.
   */
  	ec_cmd_reg = inb(sc->ec_io_nic_addr + EN_CCMD);
! 	PAGE0;
  	ec_sts_reg = inb(sc->ec_io_nic_addr + EN0_ISR);
  	outb(sc->ec_io_nic_addr + EN0_IMR, 0x0);
  loop:
***************
*** 445,451 ****
  /*
   * Reenable  onboard interrupts.
   */
! 	/*PAGE0*/
  	outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg);
  	outb(sc->ec_io_nic_addr + EN0_IMR, 0x3f);
  	if(ec_sts_reg=inb(sc->ec_io_nic_addr + EN0_ISR))
--- 565,571 ----
  /*
   * Reenable  onboard interrupts.
   */
! 	/*PAGE0;*/
  	outb(sc->ec_io_nic_addr + EN_CCMD, ec_cmd_reg);
  	outb(sc->ec_io_nic_addr + EN0_IMR, 0x3f);
  	if(ec_sts_reg=inb(sc->ec_io_nic_addr + EN0_ISR))
***************
*** 462,468 ****
  /*
   * Do some statistics.
   */
! 	PAGE0
  	sc->ec_flags &= ~EC_TXBUSY;
  	sc->ec_if.if_timer = 0;
  	++sc->ec_if.if_opackets;
--- 582,588 ----
  /*
   * Do some statistics.
   */
! 	PAGE0;
  	sc->ec_flags &= ~EC_TXBUSY;
  	sc->ec_if.if_timer = 0;
  	++sc->ec_if.if_opackets;
***************
*** 485,496 ****
  	 * Traverse the receive ring looking for packets to pass back.
  	 * The search is complete when we find a descriptor not in use.
  	 */
! 	PAGE0
  	bnry = inb(sc->ec_io_nic_addr + EN0_BOUNDARY);
! 	PAGE1
  	curr = inb(sc->ec_io_nic_addr + EN1_CURPAG);
! if(Bdry)
! 	bnry =Bdry;
  
  	while (bnry != curr)
  	{
--- 605,616 ----
  	 * Traverse the receive ring looking for packets to pass back.
  	 * The search is complete when we find a descriptor not in use.
  	 */
! 	PAGE0;
  	bnry = inb(sc->ec_io_nic_addr + EN0_BOUNDARY);
! 	PAGE1;
  	curr = inb(sc->ec_io_nic_addr + EN1_CURPAG);
! 	if(Bdry[unit])
! 		bnry = Bdry[unit];
  
  	while (bnry != curr)
  	{
***************
*** 499,509 ****
  
  		/* count includes CRC */
  		len = ecr->ec_count - 4;
! 		/*if (len > 30 && len <= ETHERMTU+100) */
  			ecread(sc, (caddr_t)(ecr + 1), len);
! 		/*else printf("reject:%x bnry:%x curr:%x", len, bnry, curr);*/
  outofbufs:
! 		PAGE0
  		/* advance on chip Boundry register */
  		if((caddr_t) ecr + EC_PAGE_SIZE - 1 > sc->ec_vmem_end) {
  			bnry = EC_RXBUF_OFFSET;
--- 619,630 ----
  
  		/* count includes CRC */
  		len = ecr->ec_count - 4;
! 		if (len > 30 && len <= ETHERMTU+100)
  			ecread(sc, (caddr_t)(ecr + 1), len);
! 		else
! 			printf("ec%d: reject - bad length %d\n", unit, len);
  outofbufs:
! 		PAGE0;
  		/* advance on chip Boundry register */
  		if((caddr_t) ecr + EC_PAGE_SIZE - 1 > sc->ec_vmem_end) {
  			bnry = EC_RXBUF_OFFSET;
***************
*** 524,541 ****
  		}
  
  		/* refresh our copy of CURR */
! 		PAGE1
  		curr = inb(sc->ec_io_nic_addr + EN1_CURPAG);
  	}
! 	Bdry = bnry;
! 	PAGE0
  }
  
! #define	ecdataaddr(sc, eh, off, type) \
! 	((type) ((caddr_t)((eh)+1)+(off) >= (sc)->ec_vmem_end) ? \
! 		(((caddr_t)((eh)+1)+(off))) - (sc)->ec_vmem_end \
  		+ (sc)->ec_vmem_ring: \
! 		((caddr_t)((eh)+1)+(off)))
  
  ecread(sc, buf, len)
  register struct ec_softc *sc;
--- 645,662 ----
  		}
  
  		/* refresh our copy of CURR */
! 		PAGE1;
  		curr = inb(sc->ec_io_nic_addr + EN1_CURPAG);
  	}
! 	Bdry[unit] = bnry;
! 	PAGE0;
  }
  
! #define	ringoffset(sc, eh, off, type) \
! 	((type) (((caddr_t)(eh)+(off) >= (sc)->ec_vmem_end) ? \
! 		(((caddr_t)(eh)+(off))) - (sc)->ec_vmem_end \
  		+ (sc)->ec_vmem_ring: \
! 		((caddr_t)(eh)+(off))))
  
  ecread(sc, buf, len)
  register struct ec_softc *sc;
***************
*** 542,581 ****
  char *buf;
  int len;
  {
! 	register struct ether_header *eh;
!     	struct mbuf *m, *ecget();
  	int off, resid;
  
! 	/*
! 	 * Deal with trailer protocol: if type is trailer type
! 	 * get true type from first 16-bit word past data.
! 	 * Remember that type was trailer by setting off.
! 	 */
  	eh = (struct ether_header *)buf;
! 	eh->ether_type = ntohs((u_short)eh->ether_type);
! 	if (eh->ether_type >= ETHERTYPE_TRAIL &&
! 	    eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
! 		off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
! 		if (off >= ETHERMTU) return;		/* sanity */
! 		eh->ether_type = ntohs(*ecdataaddr(sc, eh, off, u_short *));
! 		resid = ntohs(*(ecdataaddr(sc, eh, off+2, u_short *)));
! 		if (off + resid > len) return;		/* sanity */
! 		len = off + resid;
! 	} else	off = 0;
  
  	len -= sizeof(struct ether_header);
! 	if (len <= 0) return;
  
  	/*
! 	 * Pull packet off interface.  Off is nonzero if packet
! 	 * has trailing header; neget will then force this header
! 	 * information to be at the front, but we still have to drop
! 	 * the type and length which are at the front of any trailer data.
  	 */
! 	m = ecget(buf, len, off, &sc->ec_if, sc);
! 	if (m == 0) return;
! 	ether_input(&sc->ec_if, eh, m);
  }
  ec_ioctl(ifp, cmd, data)
  register struct ifnet *ifp;
  int cmd;
--- 663,791 ----
  char *buf;
  int len;
  {
! 	struct ether_header *eh;
!     	struct mbuf *m, *head, *ec_ring_to_mbuf();
  	int off, resid;
+ 	u_short etype;
+ 	struct trailer_header {
+ 		u_short trail_type;
+ 		u_short trail_residual;
+ 	} trailer_header;
  
! 	++sc->ec_if.if_ipackets;
! 
! 	/* Allocate a header mbuf */
! 	MGETHDR(m, M_DONTWAIT, MT_DATA);
! 	if (m == 0)
! 		goto bad;
! 	m->m_pkthdr.rcvif = &sc->ec_if;
! 	m->m_pkthdr.len = len;
! 	m->m_len = 0;
! 	head = m;
! 
  	eh = (struct ether_header *)buf;
! 
! #define EROUND	((sizeof(struct ether_header) + 3) & ~3)
! #define EOFF	(EROUND - sizeof(struct ether_header))
  
+ 	/*
+ 	 * The following assumes there is room for
+ 	 * the ether header in the header mbuf
+ 	 */
+ 	head->m_data += EOFF;
+ 	bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header));
+ 	buf += sizeof(struct ether_header);
+ 	head->m_len += sizeof(struct ether_header);
  	len -= sizeof(struct ether_header);
! 
! 	etype = ntohs((u_short) eh->ether_type);
! 
! 	/*
! 	 * Deal with trailer protocol:
! 	 * If trailer protocol, calculate the datasize as 'off',
! 	 * which is also the offset to the trailer header.
! 	 * Set resid to the amount of packet data following the
! 	 * trailer header.
! 	 * Finally, copy residual data into mbuf chain.
! 	 */
! 	if (etype >= ETHERTYPE_TRAIL &&
! 	 etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
! 
! 		off = (etype - ETHERTYPE_TRAIL) << 9;
! 		if ((off + sizeof(struct trailer_header)) > len)
! 			goto bad;	/* insanity */
! 
! 		eh->ether_type = *ringoffset(sc, buf, off, u_short *);
! 		resid = ntohs(*ringoffset(sc, buf, off+2, u_short *));
! 
! 		if ((off + resid) > len)
! 			goto bad;	/* insanity */
! 
! 		resid -= sizeof(struct trailer_header);
! 		if (resid < 0)
! 			goto bad;	/* insanity */
! 
! 		m = ec_ring_to_mbuf(sc,
! 		 ringoffset(sc, buf, off+4, char *), head, resid);
! 		if (m == 0)
! 			goto bad;
! 
! 		len = off;
! 		head->m_pkthdr.len -= 4; /* subtract trailer header */
! 	}
! 
! 	/*
! 	 * Pull packet off interface. Or if this was a trailer packet,
! 	 * the data portion is appended.
! 	 */
! 	m = ec_ring_to_mbuf(sc, buf, m, len);
! 	if (m == 0)
! 		goto bad;
! 
! #if NBPFILTER > 0
! 	/*
! 	 * Check if there's a bpf filter listening on this interface.
! 	 * If so, hand off the raw packet to bpf. 
! 	 */
! 	if (sc->ec_bpf) {
! 		bpf_mtap(sc->ec_bpf, head);
! 	}
! 
! 	/*
! 	 * Note that the interface cannot be in promiscuous mode if
! 	 * there are no bpf listeners.  And if we are in promiscuous
! 	 * mode, we have to check if this packet is really ours.
! 	 *
! 	 * XXX This test does not support multicasts.
! 	 */
! 	if ((sc->ec_if.if_flags & IFF_PROMISC) &&
! 	 bcmp(eh->ether_dhost, sc->ec_addr, sizeof(eh->ether_dhost)) != 0 &&
! 	 bcmp(eh->ether_dhost, etherbroadcastaddr,
! 	  sizeof(eh->ether_dhost)) != 0) {
! 		m_freem(head);
! 		return;
! 	}
! #endif
! 
! 	/*
! 	 * Fix up data start offset in mbuf to point past ether header
! 	 */
! 	m_adj(head, sizeof(struct ether_header));
  
  	/*
! 	 * silly ether_input routine needs 'type' in host byte order
  	 */
! 	eh->ether_type = ntohs(eh->ether_type);
! 
! 	ether_input(&sc->ec_if, eh, head);
! 	return;
! 
! bad:
! 	if (head)
! 		m_freem(head);
! 	return;
  }
+ 
  ec_ioctl(ifp, cmd, data)
  register struct ifnet *ifp;
  int cmd;
***************
*** 632,637 ****
--- 842,854 ----
  		} else if (ifp->if_flags & IFF_UP &&
  		    (ifp->if_flags & IFF_RUNNING) == 0)
  			ec_init(ifp->if_unit);
+ #if NBPFILTER > 0
+ 		if (sc->ec_if.if_flags & IFF_PROMISC)
+ 			outb(sc->ec_io_nic_addr + EN0_RXCR,
+ 			 ENRXCR_BAD | ENRXCR_PROMP | ENRXCR_BCST);
+ 		else
+ #endif /* NBPFILTER > 0 */
+ 		outb(sc->ec_io_nic_addr + EN0_RXCR, ENRXCR_BCST);
  		break;
  
  #ifdef notdef
***************
*** 660,668 ****
--- 877,889 ----
  ec_watchdog(unit)
  int unit;
  {
+ #if 1
+ 	ecintr(unit);
+ #else
  	log(LOG_WARNING, "ec%d: soft reset\n", unit);
  	ec_stop(unit);
  	ec_init(unit);
+ #endif
  }
  
  ec_stop(unit)
***************
*** 672,678 ****
  	int s;
  
  	s=splimp();
! 	PAGE0
  	outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP);
  	outb(sc->ec_io_nic_addr + EN0_IMR, 0x0);
  	sc->ec_flags &= ~EC_RUNNING;
--- 893,899 ----
  	int s;
  
  	s=splimp();
! 	PAGE0;
  	outb(sc->ec_io_nic_addr + EN_CCMD, ENC_NODMA|ENC_STOP);
  	outb(sc->ec_io_nic_addr + EN0_IMR, 0x0);
  	sc->ec_flags &= ~EC_RUNNING;
***************
*** 683,776 ****
  }
  
  /*
!  * Pull read data off a interface.
!  * Len is length of data, with local net header stripped.
!  * Off is non-zero if a trailer protocol was used, and
!  * gives the offset of the trailer information.
!  * We copy the trailer information and then all the normal
!  * data into mbufs.  When full cluster sized units are present
!  * we copy into clusters.
   */
  struct mbuf *
! ecget(buf, totlen, off0, ifp, sc)
! 	caddr_t buf;
! 	int totlen, off0;
! 	struct ifnet *ifp;
  	struct ec_softc *sc;
  {
! 	struct mbuf *top, **mp, *m, *p;
! 	int off = off0, len;
! 	register caddr_t cp = buf;
! 	char *epkt;
! 	int tc =totlen;
  
! 	buf += sizeof(struct ether_header);
! 	cp = buf;
! 	epkt = cp + totlen;
! 
! 	if (off) {
! 		cp += off + 2 * sizeof(u_short);
! 		totlen -= 2 * sizeof(u_short);
! 	}
  
! 	MGETHDR(m, M_DONTWAIT, MT_DATA);
! 	if (m == 0)
! 		return (0);
! 	m->m_pkthdr.rcvif = ifp;
! 	m->m_pkthdr.len = totlen;
! 	m->m_len = MHLEN;
! 
! 	top = 0;
! 	mp = &top;
! 	while (totlen > 0) {
! 		if (top) {
  			MGET(m, M_DONTWAIT, MT_DATA);
! 			if (m == 0) {
! 				m_freem(top);
  				return (0);
! 			}
! 			m->m_len = MLEN;
! 		}
! 		len = min(totlen, epkt - cp);
! 		if (len >= MINCLSIZE) {
  			MCLGET(m, M_DONTWAIT);
- 			if (m->m_flags & M_EXT)
- 				m->m_len = len = min(len, MCLBYTES);
- 			else
- 				len = m->m_len;
- 		} else {
- 			/*
- 			 * Place initial small packet/header at end of mbuf.
- 			 */
- 			if (len < m->m_len) {
- 				if (top == 0 && len + max_linkhdr <= m->m_len)
- 					m->m_data += max_linkhdr;
- 				m->m_len = len;
- 			} else
- 				len = m->m_len;
- 		}
  
! 		totlen -= len;
! 		/* only do up to end of buffer */
! 		if (cp+len > sc->ec_vmem_end) {
! 			unsigned toend = sc->ec_vmem_end - cp;
! 
! 			bcopy(cp, mtod(m, caddr_t), toend);
! 			cp = sc->ec_vmem_ring;
! 			bcopy(cp, mtod(m, caddr_t)+toend, len - toend);
! 			cp += len - toend;
! 			epkt = cp + totlen;
! 		} else {
! 			bcopy(cp, mtod(m, caddr_t), (unsigned)len);
! 			cp += len;
  		}
! 		*mp = m;
! 		mp = &m->m_next;
! 		if (cp == epkt) {
! 			cp = buf;
! 			epkt = cp + tc;
  		}
  	}
! 	return (top);
  }
  #endif /* NEC > 0 */
--- 904,978 ----
  }
  
  /*
!  * Copy data from receive buffer to end of mbuf chain
!  * allocate additional mbufs as needed. return pointer
!  * to last mbuf in chain.
!  * sc = ec info
!  * src = pointer in ec ring buffer
!  * dst = pointer to last mbuf in mbuf chain to copy to
!  * amount = amount of data to copy
   */
  struct mbuf *
! ec_ring_to_mbuf(sc,src,dst,total_len)
  	struct ec_softc *sc;
+ 	char *src;
+ 	struct mbuf *dst;
+ 	int total_len;
  {
! 	register struct mbuf *m = dst;
  
! 	while (total_len > 0) {
! 		register int amount = min(total_len, M_TRAILINGSPACE(m));
  
! 		if (amount == 0) { /* no more data in this mbuf, alloc another */
! 			/*
! 			 * if there is enough data for an mbuf cluster, attempt
! 			 * to allocate one of those, otherwise, a regular mbuf
! 			 * will do.
! 			 */ 
! 			dst = m;
  			MGET(m, M_DONTWAIT, MT_DATA);
! 			if (m == 0)
  				return (0);
! 
! 			if (total_len >= MINCLSIZE)
  			MCLGET(m, M_DONTWAIT);
  
! 			m->m_len = 0;
! 			dst->m_next = m;
! 			amount = min(total_len, M_TRAILINGSPACE(m));
  		}
! 
! 		src = ec_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount);
! 
! 		m->m_len += amount;
! 		total_len -= amount;
! 
  		}
+ 	return (m);
+ }
+ 
+ static inline char *
+ ec_ring_copy(sc,src,dst,amount)
+ 	struct ec_softc *sc;
+ 	char	*src;
+ 	char	*dst;
+ 	int	amount;
+ {
+ 	int	tmp_amount;
+ 
+ 	/* does copy wrap to lower addr in ring buffer? */
+ 	if (src + amount > sc->ec_vmem_end) {
+ 		tmp_amount = sc->ec_vmem_end - src;
+ 		bcopy(src,dst,tmp_amount); /* copy amount up to end */
+ 		amount -= tmp_amount;
+ 		src = sc->ec_vmem_ring;
+ 		dst += tmp_amount;
  	}
! 
! 	bcopy(src, dst, amount);
! 
! 	return(src + amount);
  }
  #endif /* NEC > 0 */
+ 
============================== cut here ==============================