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