*BSD News Article 23270


Return to BSD News archive

Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!cronkite.cisco.com!cisco.com!vandys
From: vandys@cisco.com (Andrew Valencia)
Newsgroups: comp.os.386bsd.development
Subject: if_ne support for BPF
Date: 4 Nov 93 00:45:46 GMT
Organization: cisco Systems
Lines: 337
Message-ID: <vandys.752373946@cisco.com>
NNTP-Posting-Host: glare.cisco.com

I needed to do some tcpdump'ing off my 386BSD machine and found that
the if_ne driver for my NE2000 didn't have BPF support.  I stole
from the if_we.c and if_loop.c drivers, and the result seems to work
pretty well.  I didn't have any technical docs for the NE2000, so if
I got the promiscuous part wrong, please let me know.  It *does*
seem to work--your mileage may vary.

These patches are a derivative work of the named sources, and I provide
them as-is.  My system is at patch level 0.2.3; if this has been done in
a later patch level please ignore it.

					Andy Valencia
					vandys@cisco.com

*** /tmp/,RCSt1000079	Wed Nov  3 17:31:44 1993
--- if_ne.c	Wed Nov  3 17:07:41 1993
***************
*** 71,76 ****
--- 71,81 ----
  #include "netns/ns_if.h"
  #endif
  
+ #include "bpfilter.h"
+ #if NBPFILTER > 0
+ #include "net/bpf.h"
+ #include "net/bpfdesc.h"
+ #endif
  #include "i386/isa/isa_device.h"
  #include "i386/isa/if_nereg.h"
  #include "i386/isa/icu.h"
***************
*** 82,89 ****
  	neprobe, neattach, "ne",
  };
  
- struct	mbuf *neget();
- 
  #define ETHER_MIN_LEN 64
  #define ETHER_MAX_LEN 1536
  
--- 87,92 ----
***************
*** 100,105 ****
--- 103,111 ----
  #define	ns_addr	ns_ac.ac_enaddr		/* hardware Ethernet address */
  	int	ns_flags;
  #define	DSF_LOCK	1		/* block re-entering enstart */
+ #if NBPFILTER > 0
+ #define DSF_ATTACHED 0x80
+ #endif
  	int	ns_oactive ;
  	int	ns_mask ;
  	int	ns_ba;			/* byte addr in buffer ram of inc pkt */
***************
*** 112,122 ****
--- 118,130 ----
  	short	ns_rxbndry;		/* recevier buffer boundary */
  	short	ns_port;		/* i/o port base */
  	short	ns_mode;		/* word/byte mode */
+ 	caddr_t	ns_bpf;			/* Magic Cookie for BPF */
  } ne_softc[NNE] ;
  #define	ENBUFSIZE	(sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN)
  
  #define	PAT(n)	(0xa55a + 37*(n))
  
+ static struct mbuf *neget(caddr_t, int, int, struct ne_softc *);
  u_short boarddata[16];
   
  neprobe(dvp)
***************
*** 342,347 ****
--- 350,371 ----
  	ifp->if_reset = nereset;
  	ifp->if_watchdog = 0;
  	if_attach(ifp);
+ 	ns->ns_flags &= ~DSF_ATTACHED;	/* Make sure BPF attach flag clear */
+ }
+ 
+ /*
+  * set_rcr()
+  *	Apply appropriate bits to receive control register
+  */
+ static inline void
+ set_rcr(struct ne_softc *ns)
+ {
+ #if NBPFILTER > 0
+ 	if (ns->ns_if.if_flags & IFF_PROMISC) {
+ 		outb(ns->ns_port + ds0_rcr, DSRC_AB|DSRC_PRO);
+ 	} else
+ #endif
+ 		outb(ns->ns_port + ds0_rcr, DSRC_AB);
  }
  
  /*
***************
*** 357,362 ****
--- 381,393 ----
  	int i; char *cp;
  	register nec = ns->ns_port;
  
+ #if NBPFILTER > 0
+ 	if ((ns->ns_flags & DSF_ATTACHED) == 0) {
+ 		bpfattach(&ns->ns_bpf, ifp, DLT_EN10MB,
+ 			sizeof(struct ether_header));
+ 		ns->ns_flags |= DSF_ATTACHED;
+ 	}
+ #endif
   	if (ifp->if_addrlist == (struct ifaddr *)0) return;
  	if (ifp->if_flags & IFF_RUNNING) return;
  
***************
*** 389,395 ****
  	outb(nec+ds1_curr, (ns->ns_txstart+PKTSZ)/DS_PGSIZE);
  	ns->ns_cur = (ns->ns_txstart+PKTSZ)/DS_PGSIZE;
  	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
! 	outb (nec+ds0_rcr, DSRC_AB);
  	outb(nec+ds0_dcr, ns->ns_mode);
  	outb (nec+ds0_imr, 0xff);
  
--- 420,427 ----
  	outb(nec+ds1_curr, (ns->ns_txstart+PKTSZ)/DS_PGSIZE);
  	ns->ns_cur = (ns->ns_txstart+PKTSZ)/DS_PGSIZE;
  	outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
! 	set_rcr(ns);
! 
  	outb(nec+ds0_dcr, ns->ns_mode);
  	outb (nec+ds0_imr, 0xff);
  
***************
*** 444,451 ****
  	t = 0;
  	for (m0 = m; m != 0; m = m->m_next)
  		t += m->m_len;
- 		
  	m = m0;
  	total = t;
  	for (m0 = m; m != 0; ) {
  		
--- 476,530 ----
  	t = 0;
  	for (m0 = m; m != 0; m = m->m_next)
  		t += m->m_len;
  	m = m0;
+ #if NBPFILTER > 0
+ 	if (ns->ns_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;
+ 
+ 		/* 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(ns->ns_bpf, ether_packet, ep - ether_packet);
+ 		} else {
+ 			bpf_mtap(ns->ns_bpf, m);
+ 		}
+ 	}
+ #endif
+ 
  	total = t;
  	for (m0 = m; m != 0; ) {
  		
***************
*** 660,665 ****
--- 739,745 ----
      	struct mbuf *m;
  	int off, resid;
  	register struct ifqueue *inq;
+ 	u_short etype;
  
  	/*
  	 * Deal with trailer protocol: if type is trailer type
***************
*** 667,679 ****
  	 * Remember that type was trailer by setting off.
  	 */
  	eh = (struct ether_header *)buf;
! 	eh->ether_type = ntohs((u_short)eh->ether_type);
  #define	nedataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
! 	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(*nedataaddr(eh, off, u_short *));
  		resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
  		if (off + resid > len) return;		/* sanity */
  		len = off + resid;
--- 747,759 ----
  	 * Remember that type was trailer by setting off.
  	 */
  	eh = (struct ether_header *)buf;
! 	etype = ntohs((u_short)eh->ether_type);
  #define	nedataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
! 	if (etype >= ETHERTYPE_TRAIL &&
! 	    etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
! 		off = (etype - ETHERTYPE_TRAIL) << 9;
  		if (off >= ETHERMTU) return;		/* sanity */
! 		etype = ntohs(*nedataaddr(eh, off, u_short *));
  		resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
  		if (off + resid > len) return;		/* sanity */
  		len = off + resid;
***************
*** 687,695 ****
  	 * 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 = neget(buf, len, off, &ns->ns_if);
  	if (m == 0) return;
  
  	ether_input(&ns->ns_if, eh, m);
  }
  
--- 767,813 ----
  	 * 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 = neget(buf, len, off, ns);
  	if (m == 0) return;
  
+ #if NBPFILTER > 0
+ 	/*
+ 	 * Check if there's a bpf filter listening on this interface.
+ 	 * If so, hand off the raw packet to bpf. 
+ 	 */
+ 	if (ns->ns_bpf) {
+ 		struct mbuf m0;
+ 
+ 		/*
+ 		 * BPF wants to see the ether header at the front of the
+ 		 * packet.  neget() doesn't do that, so we create * a
+ 		 * pseudo-mbuf just long enough to fool bpf_mtap().
+ 		 */
+ 		m0.m_next = m;
+ 		m0.m_len = sizeof(struct ether_header);
+ 		m0.m_data = buf;
+ 		bpf_mtap(ns->ns_bpf, &m0);
+ 	}
+ 
+ 	/*
+ 	 * If in promiscuous, dump packets which aren't for our protocol
+ 	 * stack.
+ 	 */
+ #define ESZ sizeof(eh->ether_dhost)
+ 	if ((ns->ns_if.if_flags & IFF_PROMISC) &&
+ 			bcmp(eh->ether_dhost, ns->ns_addr, ESZ) &&
+ 			bcmp(eh->ether_dhost, etherbroadcastaddr, ESZ)) {
+ 		m_freem(m);
+ 		return;
+ 	}
+ #undef ESZ
+ #endif
+ 	/*
+ 	 * Now map ether_type into host-format true ether type.  BPF
+ 	 * wants net format, so we kept it in a local variable until
+ 	 * he was done.
+ 	 */
+ 	eh->ether_type = etype;
  	ether_input(&ns->ns_if, eh, m);
  }
  
***************
*** 706,721 ****
   * data into mbufs.  When full cluster sized units are present
   * we copy into clusters.
   */
! struct mbuf *
! neget(buf, totlen, off0, ifp)
! 	caddr_t buf;
! 	int totlen, off0;
! 	struct ifnet *ifp;
  {
  	struct mbuf *top, **mp, *m, *p;
  	int off = off0, len;
! 	register caddr_t cp = buf;
  	char *epkt;
  
  	buf += sizeof(struct ether_header);
  	cp = buf;
--- 824,837 ----
   * data into mbufs.  When full cluster sized units are present
   * we copy into clusters.
   */
! static struct mbuf *
! neget(caddr_t buf, int totlen, int off0, struct ne_softc *ns)
  {
  	struct mbuf *top, **mp, *m, *p;
  	int off = off0, len;
! 	caddr_t cp = buf;
  	char *epkt;
+ 	struct ifnet *ifp = &ns->ns_if;
  
  	buf += sizeof(struct ether_header);
  	cp = buf;
***************
*** 837,842 ****
--- 953,961 ----
  		} else if (ifp->if_flags & IFF_UP &&
  		    (ifp->if_flags & IFF_RUNNING) == 0)
  			neinit(ifp->if_unit);
+ #if NBPFILTER > 0
+ 		set_rcr(ns);
+ #endif
  		break;
  
  #ifdef notdef