1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1990, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * This code is derived from the Stanford/CMU enet packet filter, 6df8bae1dSRodney W. Grimes * (net/enet.c) distributed as part of 4.3BSD, and code contributed 7df8bae1dSRodney W. Grimes * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence 8df8bae1dSRodney W. Grimes * Berkeley Laboratory. 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 18df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 19df8bae1dSRodney W. Grimes * must display the following acknowledgement: 20df8bae1dSRodney W. Grimes * This product includes software developed by the University of 21df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 22df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 23df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 24df8bae1dSRodney W. Grimes * without specific prior written permission. 25df8bae1dSRodney W. Grimes * 26df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36df8bae1dSRodney W. Grimes * SUCH DAMAGE. 37df8bae1dSRodney W. Grimes * 38df8bae1dSRodney W. Grimes * @(#)bpf.c 8.2 (Berkeley) 3/28/94 39df8bae1dSRodney W. Grimes * 400310c19fSBruce Evans * $Id: bpf.c,v 1.17 1995/12/02 19:37:19 bde Exp $ 41df8bae1dSRodney W. Grimes */ 42df8bae1dSRodney W. Grimes 43df8bae1dSRodney W. Grimes #include "bpfilter.h" 44df8bae1dSRodney W. Grimes 45df8bae1dSRodney W. Grimes #if NBPFILTER > 0 46df8bae1dSRodney W. Grimes 47df8bae1dSRodney W. Grimes #ifndef __GNUC__ 48df8bae1dSRodney W. Grimes #define inline 49df8bae1dSRodney W. Grimes #else 50df8bae1dSRodney W. Grimes #define inline __inline 51df8bae1dSRodney W. Grimes #endif 52df8bae1dSRodney W. Grimes 53df8bae1dSRodney W. Grimes #include <sys/param.h> 54df8bae1dSRodney W. Grimes #include <sys/systm.h> 55ce7609a4SBruce Evans #include <sys/conf.h> 562eeab939SGarrett Wollman #include <machine/cpu.h> /* for bootverbose */ 57df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 58df8bae1dSRodney W. Grimes #include <sys/buf.h> 59df8bae1dSRodney W. Grimes #include <sys/time.h> 60df8bae1dSRodney W. Grimes #include <sys/proc.h> 610310c19fSBruce Evans #include <sys/signalvar.h> 62df8bae1dSRodney W. Grimes #include <sys/ioctl.h> 63df8bae1dSRodney W. Grimes 64df8bae1dSRodney W. Grimes #include <sys/file.h> 65df8bae1dSRodney W. Grimes #if defined(sparc) && BSD < 199103 66df8bae1dSRodney W. Grimes #include <sys/stream.h> 67df8bae1dSRodney W. Grimes #endif 68df8bae1dSRodney W. Grimes #include <sys/uio.h> 69df8bae1dSRodney W. Grimes 70df8bae1dSRodney W. Grimes #include <sys/socket.h> 71c9d16071SPoul-Henning Kamp #include <sys/socketvar.h> 72c9d16071SPoul-Henning Kamp #include <sys/protosw.h> 73df8bae1dSRodney W. Grimes #include <net/if.h> 74df8bae1dSRodney W. Grimes 75df8bae1dSRodney W. Grimes #include <net/bpf.h> 76df8bae1dSRodney W. Grimes #include <net/bpfdesc.h> 77df8bae1dSRodney W. Grimes 78df8bae1dSRodney W. Grimes #include <sys/errno.h> 79df8bae1dSRodney W. Grimes 80df8bae1dSRodney W. Grimes #include <netinet/in.h> 81df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 82df8bae1dSRodney W. Grimes #include <sys/kernel.h> 83df8bae1dSRodney W. Grimes 8453ac6efbSJulian Elischer #ifdef JREMOD 8553ac6efbSJulian Elischer #include <sys/conf.h> 8653ac6efbSJulian Elischer #ifdef DEVFS 8753ac6efbSJulian Elischer #include <sys/devfsext.h> 8853ac6efbSJulian Elischer #endif /*DEVFS*/ 8953ac6efbSJulian Elischer #define CDEV_MAJOR 23 9053ac6efbSJulian Elischer #endif /*JREMOD*/ 9153ac6efbSJulian Elischer 92df8bae1dSRodney W. Grimes /* 93df8bae1dSRodney W. Grimes * Older BSDs don't have kernel malloc. 94df8bae1dSRodney W. Grimes */ 95df8bae1dSRodney W. Grimes #if BSD < 199103 96df8bae1dSRodney W. Grimes extern bcopy(); 97df8bae1dSRodney W. Grimes static caddr_t bpf_alloc(); 98df8bae1dSRodney W. Grimes #include <net/bpf_compat.h> 99df8bae1dSRodney W. Grimes #define BPF_BUFSIZE (MCLBYTES-8) 100df8bae1dSRodney W. Grimes #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio) 101df8bae1dSRodney W. Grimes #else 102df8bae1dSRodney W. Grimes #define BPF_BUFSIZE 4096 103df8bae1dSRodney W. Grimes #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio) 104df8bae1dSRodney W. Grimes #endif 105df8bae1dSRodney W. Grimes 106df8bae1dSRodney W. Grimes #define PRINET 26 /* interruptible */ 107df8bae1dSRodney W. Grimes 108df8bae1dSRodney W. Grimes /* 109df8bae1dSRodney W. Grimes * The default read buffer size is patchable. 110df8bae1dSRodney W. Grimes */ 111df8bae1dSRodney W. Grimes int bpf_bufsize = BPF_BUFSIZE; 112df8bae1dSRodney W. Grimes 113df8bae1dSRodney W. Grimes /* 114df8bae1dSRodney W. Grimes * bpf_iflist is the list of interfaces; each corresponds to an ifnet 115df8bae1dSRodney W. Grimes * bpf_dtab holds the descriptors, indexed by minor device # 116df8bae1dSRodney W. Grimes */ 117df8bae1dSRodney W. Grimes struct bpf_if *bpf_iflist; 118df8bae1dSRodney W. Grimes struct bpf_d bpf_dtab[NBPFILTER]; 119df8bae1dSRodney W. Grimes 120df8bae1dSRodney W. Grimes #if BSD >= 199207 121df8bae1dSRodney W. Grimes /* 122df8bae1dSRodney W. Grimes * bpfilterattach() is called at boot time in new systems. We do 123df8bae1dSRodney W. Grimes * nothing here since old systems will not call this. 124df8bae1dSRodney W. Grimes */ 125df8bae1dSRodney W. Grimes /* ARGSUSED */ 126df8bae1dSRodney W. Grimes void 127df8bae1dSRodney W. Grimes bpfilterattach(n) 128df8bae1dSRodney W. Grimes int n; 129df8bae1dSRodney W. Grimes { 130df8bae1dSRodney W. Grimes } 131df8bae1dSRodney W. Grimes #endif 132df8bae1dSRodney W. Grimes 133df8bae1dSRodney W. Grimes static int bpf_allocbufs __P((struct bpf_d *)); 134ce7609a4SBruce Evans static void bpf_attachd __P((struct bpf_d *d, struct bpf_if *bp)); 135ce7609a4SBruce Evans static void bpf_detachd __P((struct bpf_d *d)); 136df8bae1dSRodney W. Grimes static void bpf_freed __P((struct bpf_d *)); 137df8bae1dSRodney W. Grimes static void bpf_ifname __P((struct ifnet *, struct ifreq *)); 138df8bae1dSRodney W. Grimes static void bpf_mcopy __P((const void *, void *, u_int)); 139df8bae1dSRodney W. Grimes static int bpf_movein __P((struct uio *, int, 140df8bae1dSRodney W. Grimes struct mbuf **, struct sockaddr *, int *)); 141df8bae1dSRodney W. Grimes static int bpf_setif __P((struct bpf_d *, struct ifreq *)); 142df8bae1dSRodney W. Grimes static inline void 143df8bae1dSRodney W. Grimes bpf_wakeup __P((struct bpf_d *)); 144df8bae1dSRodney W. Grimes static void catchpacket __P((struct bpf_d *, u_char *, u_int, 145df8bae1dSRodney W. Grimes u_int, void (*)(const void *, void *, u_int))); 146df8bae1dSRodney W. Grimes static void reset_d __P((struct bpf_d *)); 147df8bae1dSRodney W. Grimes 148df8bae1dSRodney W. Grimes static int 149df8bae1dSRodney W. Grimes bpf_movein(uio, linktype, mp, sockp, datlen) 150df8bae1dSRodney W. Grimes register struct uio *uio; 151df8bae1dSRodney W. Grimes int linktype, *datlen; 152df8bae1dSRodney W. Grimes register struct mbuf **mp; 153df8bae1dSRodney W. Grimes register struct sockaddr *sockp; 154df8bae1dSRodney W. Grimes { 155df8bae1dSRodney W. Grimes struct mbuf *m; 156df8bae1dSRodney W. Grimes int error; 157df8bae1dSRodney W. Grimes int len; 158df8bae1dSRodney W. Grimes int hlen; 159df8bae1dSRodney W. Grimes 160df8bae1dSRodney W. Grimes /* 161df8bae1dSRodney W. Grimes * Build a sockaddr based on the data link layer type. 162df8bae1dSRodney W. Grimes * We do this at this level because the ethernet header 163df8bae1dSRodney W. Grimes * is copied directly into the data field of the sockaddr. 164df8bae1dSRodney W. Grimes * In the case of SLIP, there is no header and the packet 165df8bae1dSRodney W. Grimes * is forwarded as is. 166df8bae1dSRodney W. Grimes * Also, we are careful to leave room at the front of the mbuf 167df8bae1dSRodney W. Grimes * for the link level header. 168df8bae1dSRodney W. Grimes */ 169df8bae1dSRodney W. Grimes switch (linktype) { 170df8bae1dSRodney W. Grimes 171df8bae1dSRodney W. Grimes case DLT_SLIP: 172df8bae1dSRodney W. Grimes sockp->sa_family = AF_INET; 173df8bae1dSRodney W. Grimes hlen = 0; 174df8bae1dSRodney W. Grimes break; 175df8bae1dSRodney W. Grimes 176df8bae1dSRodney W. Grimes case DLT_EN10MB: 177df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 178df8bae1dSRodney W. Grimes /* XXX Would MAXLINKHDR be better? */ 179df8bae1dSRodney W. Grimes hlen = sizeof(struct ether_header); 180df8bae1dSRodney W. Grimes break; 181df8bae1dSRodney W. Grimes 182df8bae1dSRodney W. Grimes case DLT_FDDI: 183d41f24e7SDavid Greenman #if defined(__FreeBSD__) || defined(__bsdi__) 184d41f24e7SDavid Greenman sockp->sa_family = AF_IMPLINK; 185d41f24e7SDavid Greenman hlen = 0; 186d41f24e7SDavid Greenman #else 187df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 188df8bae1dSRodney W. Grimes /* XXX 4(FORMAC)+6(dst)+6(src)+3(LLC)+5(SNAP) */ 189df8bae1dSRodney W. Grimes hlen = 24; 190d41f24e7SDavid Greenman #endif 191df8bae1dSRodney W. Grimes break; 192df8bae1dSRodney W. Grimes 193df8bae1dSRodney W. Grimes case DLT_NULL: 194df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 195df8bae1dSRodney W. Grimes hlen = 0; 196df8bae1dSRodney W. Grimes break; 197df8bae1dSRodney W. Grimes 198df8bae1dSRodney W. Grimes default: 199df8bae1dSRodney W. Grimes return (EIO); 200df8bae1dSRodney W. Grimes } 201df8bae1dSRodney W. Grimes 202df8bae1dSRodney W. Grimes len = uio->uio_resid; 203df8bae1dSRodney W. Grimes *datlen = len - hlen; 204df8bae1dSRodney W. Grimes if ((unsigned)len > MCLBYTES) 205df8bae1dSRodney W. Grimes return (EIO); 206df8bae1dSRodney W. Grimes 207963e4c2aSGarrett Wollman MGETHDR(m, M_WAIT, MT_DATA); 208df8bae1dSRodney W. Grimes if (m == 0) 209df8bae1dSRodney W. Grimes return (ENOBUFS); 210963e4c2aSGarrett Wollman if (len > MHLEN) { 211df8bae1dSRodney W. Grimes #if BSD >= 199103 212df8bae1dSRodney W. Grimes MCLGET(m, M_WAIT); 213df8bae1dSRodney W. Grimes if ((m->m_flags & M_EXT) == 0) { 214df8bae1dSRodney W. Grimes #else 215df8bae1dSRodney W. Grimes MCLGET(m); 216df8bae1dSRodney W. Grimes if (m->m_len != MCLBYTES) { 217df8bae1dSRodney W. Grimes #endif 218df8bae1dSRodney W. Grimes error = ENOBUFS; 219df8bae1dSRodney W. Grimes goto bad; 220df8bae1dSRodney W. Grimes } 221df8bae1dSRodney W. Grimes } 222963e4c2aSGarrett Wollman m->m_pkthdr.len = m->m_len = len; 223963e4c2aSGarrett Wollman m->m_pkthdr.rcvif = NULL; 224df8bae1dSRodney W. Grimes *mp = m; 225df8bae1dSRodney W. Grimes /* 226df8bae1dSRodney W. Grimes * Make room for link header. 227df8bae1dSRodney W. Grimes */ 228df8bae1dSRodney W. Grimes if (hlen != 0) { 229df8bae1dSRodney W. Grimes m->m_len -= hlen; 230df8bae1dSRodney W. Grimes #if BSD >= 199103 231df8bae1dSRodney W. Grimes m->m_data += hlen; /* XXX */ 232df8bae1dSRodney W. Grimes #else 233df8bae1dSRodney W. Grimes m->m_off += hlen; 234df8bae1dSRodney W. Grimes #endif 235df8bae1dSRodney W. Grimes error = UIOMOVE((caddr_t)sockp->sa_data, hlen, UIO_WRITE, uio); 236df8bae1dSRodney W. Grimes if (error) 237df8bae1dSRodney W. Grimes goto bad; 238df8bae1dSRodney W. Grimes } 239df8bae1dSRodney W. Grimes error = UIOMOVE(mtod(m, caddr_t), len - hlen, UIO_WRITE, uio); 240df8bae1dSRodney W. Grimes if (!error) 241df8bae1dSRodney W. Grimes return (0); 242df8bae1dSRodney W. Grimes bad: 243df8bae1dSRodney W. Grimes m_freem(m); 244df8bae1dSRodney W. Grimes return (error); 245df8bae1dSRodney W. Grimes } 246df8bae1dSRodney W. Grimes 247df8bae1dSRodney W. Grimes /* 248df8bae1dSRodney W. Grimes * Attach file to the bpf interface, i.e. make d listen on bp. 249df8bae1dSRodney W. Grimes * Must be called at splimp. 250df8bae1dSRodney W. Grimes */ 251df8bae1dSRodney W. Grimes static void 252df8bae1dSRodney W. Grimes bpf_attachd(d, bp) 253df8bae1dSRodney W. Grimes struct bpf_d *d; 254df8bae1dSRodney W. Grimes struct bpf_if *bp; 255df8bae1dSRodney W. Grimes { 256df8bae1dSRodney W. Grimes /* 257df8bae1dSRodney W. Grimes * Point d at bp, and add d to the interface's list of listeners. 258df8bae1dSRodney W. Grimes * Finally, point the driver's bpf cookie at the interface so 259df8bae1dSRodney W. Grimes * it will divert packets to bpf. 260df8bae1dSRodney W. Grimes */ 261df8bae1dSRodney W. Grimes d->bd_bif = bp; 262df8bae1dSRodney W. Grimes d->bd_next = bp->bif_dlist; 263df8bae1dSRodney W. Grimes bp->bif_dlist = d; 264df8bae1dSRodney W. Grimes 265df8bae1dSRodney W. Grimes *bp->bif_driverp = bp; 266df8bae1dSRodney W. Grimes } 267df8bae1dSRodney W. Grimes 268df8bae1dSRodney W. Grimes /* 269df8bae1dSRodney W. Grimes * Detach a file from its interface. 270df8bae1dSRodney W. Grimes */ 271df8bae1dSRodney W. Grimes static void 272df8bae1dSRodney W. Grimes bpf_detachd(d) 273df8bae1dSRodney W. Grimes struct bpf_d *d; 274df8bae1dSRodney W. Grimes { 275df8bae1dSRodney W. Grimes struct bpf_d **p; 276df8bae1dSRodney W. Grimes struct bpf_if *bp; 277df8bae1dSRodney W. Grimes 278df8bae1dSRodney W. Grimes bp = d->bd_bif; 279df8bae1dSRodney W. Grimes /* 280df8bae1dSRodney W. Grimes * Check if this descriptor had requested promiscuous mode. 281df8bae1dSRodney W. Grimes * If so, turn it off. 282df8bae1dSRodney W. Grimes */ 283df8bae1dSRodney W. Grimes if (d->bd_promisc) { 284df8bae1dSRodney W. Grimes d->bd_promisc = 0; 285df8bae1dSRodney W. Grimes if (ifpromisc(bp->bif_ifp, 0)) 286df8bae1dSRodney W. Grimes /* 287df8bae1dSRodney W. Grimes * Something is really wrong if we were able to put 288df8bae1dSRodney W. Grimes * the driver into promiscuous mode, but can't 289df8bae1dSRodney W. Grimes * take it out. 290df8bae1dSRodney W. Grimes */ 291df8bae1dSRodney W. Grimes panic("bpf: ifpromisc failed"); 292df8bae1dSRodney W. Grimes } 293df8bae1dSRodney W. Grimes /* Remove d from the interface's descriptor list. */ 294df8bae1dSRodney W. Grimes p = &bp->bif_dlist; 295df8bae1dSRodney W. Grimes while (*p != d) { 296df8bae1dSRodney W. Grimes p = &(*p)->bd_next; 297df8bae1dSRodney W. Grimes if (*p == 0) 298df8bae1dSRodney W. Grimes panic("bpf_detachd: descriptor not in list"); 299df8bae1dSRodney W. Grimes } 300df8bae1dSRodney W. Grimes *p = (*p)->bd_next; 301df8bae1dSRodney W. Grimes if (bp->bif_dlist == 0) 302df8bae1dSRodney W. Grimes /* 303df8bae1dSRodney W. Grimes * Let the driver know that there are no more listeners. 304df8bae1dSRodney W. Grimes */ 305df8bae1dSRodney W. Grimes *d->bd_bif->bif_driverp = 0; 306df8bae1dSRodney W. Grimes d->bd_bif = 0; 307df8bae1dSRodney W. Grimes } 308df8bae1dSRodney W. Grimes 309df8bae1dSRodney W. Grimes 310df8bae1dSRodney W. Grimes /* 311df8bae1dSRodney W. Grimes * Mark a descriptor free by making it point to itself. 312df8bae1dSRodney W. Grimes * This is probably cheaper than marking with a constant since 313df8bae1dSRodney W. Grimes * the address should be in a register anyway. 314df8bae1dSRodney W. Grimes */ 315df8bae1dSRodney W. Grimes #define D_ISFREE(d) ((d) == (d)->bd_next) 316df8bae1dSRodney W. Grimes #define D_MARKFREE(d) ((d)->bd_next = (d)) 317df8bae1dSRodney W. Grimes #define D_MARKUSED(d) ((d)->bd_next = 0) 318df8bae1dSRodney W. Grimes 319df8bae1dSRodney W. Grimes /* 320df8bae1dSRodney W. Grimes * Open ethernet device. Returns ENXIO for illegal minor device number, 321df8bae1dSRodney W. Grimes * EBUSY if file is open by another process. 322df8bae1dSRodney W. Grimes */ 323df8bae1dSRodney W. Grimes /* ARGSUSED */ 324df8bae1dSRodney W. Grimes int 32560039670SBruce Evans bpfopen(dev, flags, fmt, p) 326df8bae1dSRodney W. Grimes dev_t dev; 32760039670SBruce Evans int flags; 32860039670SBruce Evans int fmt; 32960039670SBruce Evans struct proc *p; 330df8bae1dSRodney W. Grimes { 331df8bae1dSRodney W. Grimes register struct bpf_d *d; 332df8bae1dSRodney W. Grimes 333df8bae1dSRodney W. Grimes if (minor(dev) >= NBPFILTER) 334df8bae1dSRodney W. Grimes return (ENXIO); 335df8bae1dSRodney W. Grimes /* 336df8bae1dSRodney W. Grimes * Each minor can be opened by only one process. If the requested 337df8bae1dSRodney W. Grimes * minor is in use, return EBUSY. 338df8bae1dSRodney W. Grimes */ 339df8bae1dSRodney W. Grimes d = &bpf_dtab[minor(dev)]; 340df8bae1dSRodney W. Grimes if (!D_ISFREE(d)) 341df8bae1dSRodney W. Grimes return (EBUSY); 342df8bae1dSRodney W. Grimes 343df8bae1dSRodney W. Grimes /* Mark "free" and do most initialization. */ 344df8bae1dSRodney W. Grimes bzero((char *)d, sizeof(*d)); 345df8bae1dSRodney W. Grimes d->bd_bufsize = bpf_bufsize; 34600a83887SPaul Traina d->bd_sig = SIGIO; 347df8bae1dSRodney W. Grimes 348df8bae1dSRodney W. Grimes return (0); 349df8bae1dSRodney W. Grimes } 350df8bae1dSRodney W. Grimes 351df8bae1dSRodney W. Grimes /* 352df8bae1dSRodney W. Grimes * Close the descriptor by detaching it from its interface, 353df8bae1dSRodney W. Grimes * deallocating its buffers, and marking it free. 354df8bae1dSRodney W. Grimes */ 355df8bae1dSRodney W. Grimes /* ARGSUSED */ 356df8bae1dSRodney W. Grimes int 35760039670SBruce Evans bpfclose(dev, flags, fmt, p) 358df8bae1dSRodney W. Grimes dev_t dev; 35960039670SBruce Evans int flags; 36060039670SBruce Evans int fmt; 36160039670SBruce Evans struct proc *p; 362df8bae1dSRodney W. Grimes { 363df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 364df8bae1dSRodney W. Grimes register int s; 365df8bae1dSRodney W. Grimes 366df8bae1dSRodney W. Grimes s = splimp(); 367df8bae1dSRodney W. Grimes if (d->bd_bif) 368df8bae1dSRodney W. Grimes bpf_detachd(d); 369df8bae1dSRodney W. Grimes splx(s); 370df8bae1dSRodney W. Grimes bpf_freed(d); 371df8bae1dSRodney W. Grimes 372df8bae1dSRodney W. Grimes return (0); 373df8bae1dSRodney W. Grimes } 374df8bae1dSRodney W. Grimes 375df8bae1dSRodney W. Grimes /* 376df8bae1dSRodney W. Grimes * Support for SunOS, which does not have tsleep. 377df8bae1dSRodney W. Grimes */ 378df8bae1dSRodney W. Grimes #if BSD < 199103 379df8bae1dSRodney W. Grimes static 380df8bae1dSRodney W. Grimes bpf_timeout(arg) 381df8bae1dSRodney W. Grimes caddr_t arg; 382df8bae1dSRodney W. Grimes { 383df8bae1dSRodney W. Grimes struct bpf_d *d = (struct bpf_d *)arg; 384df8bae1dSRodney W. Grimes d->bd_timedout = 1; 385df8bae1dSRodney W. Grimes wakeup(arg); 386df8bae1dSRodney W. Grimes } 387df8bae1dSRodney W. Grimes 388df8bae1dSRodney W. Grimes #define BPF_SLEEP(chan, pri, s, t) bpf_sleep((struct bpf_d *)chan) 389df8bae1dSRodney W. Grimes 390df8bae1dSRodney W. Grimes int 391df8bae1dSRodney W. Grimes bpf_sleep(d) 392df8bae1dSRodney W. Grimes register struct bpf_d *d; 393df8bae1dSRodney W. Grimes { 394df8bae1dSRodney W. Grimes register int rto = d->bd_rtout; 395df8bae1dSRodney W. Grimes register int st; 396df8bae1dSRodney W. Grimes 397df8bae1dSRodney W. Grimes if (rto != 0) { 398df8bae1dSRodney W. Grimes d->bd_timedout = 0; 399df8bae1dSRodney W. Grimes timeout(bpf_timeout, (caddr_t)d, rto); 400df8bae1dSRodney W. Grimes } 401df8bae1dSRodney W. Grimes st = sleep((caddr_t)d, PRINET|PCATCH); 402df8bae1dSRodney W. Grimes if (rto != 0) { 403df8bae1dSRodney W. Grimes if (d->bd_timedout == 0) 404df8bae1dSRodney W. Grimes untimeout(bpf_timeout, (caddr_t)d); 405df8bae1dSRodney W. Grimes else if (st == 0) 406df8bae1dSRodney W. Grimes return EWOULDBLOCK; 407df8bae1dSRodney W. Grimes } 408df8bae1dSRodney W. Grimes return (st != 0) ? EINTR : 0; 409df8bae1dSRodney W. Grimes } 410df8bae1dSRodney W. Grimes #else 411df8bae1dSRodney W. Grimes #define BPF_SLEEP tsleep 412df8bae1dSRodney W. Grimes #endif 413df8bae1dSRodney W. Grimes 414df8bae1dSRodney W. Grimes /* 415df8bae1dSRodney W. Grimes * Rotate the packet buffers in descriptor d. Move the store buffer 416df8bae1dSRodney W. Grimes * into the hold slot, and the free buffer into the store slot. 417df8bae1dSRodney W. Grimes * Zero the length of the new store buffer. 418df8bae1dSRodney W. Grimes */ 419df8bae1dSRodney W. Grimes #define ROTATE_BUFFERS(d) \ 420df8bae1dSRodney W. Grimes (d)->bd_hbuf = (d)->bd_sbuf; \ 421df8bae1dSRodney W. Grimes (d)->bd_hlen = (d)->bd_slen; \ 422df8bae1dSRodney W. Grimes (d)->bd_sbuf = (d)->bd_fbuf; \ 423df8bae1dSRodney W. Grimes (d)->bd_slen = 0; \ 424df8bae1dSRodney W. Grimes (d)->bd_fbuf = 0; 425df8bae1dSRodney W. Grimes /* 426df8bae1dSRodney W. Grimes * bpfread - read next chunk of packets from buffers 427df8bae1dSRodney W. Grimes */ 428df8bae1dSRodney W. Grimes int 42960039670SBruce Evans bpfread(dev, uio, ioflag) 430df8bae1dSRodney W. Grimes dev_t dev; 431df8bae1dSRodney W. Grimes register struct uio *uio; 43260039670SBruce Evans int ioflag; 433df8bae1dSRodney W. Grimes { 434df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 435df8bae1dSRodney W. Grimes int error; 436df8bae1dSRodney W. Grimes int s; 437df8bae1dSRodney W. Grimes 438df8bae1dSRodney W. Grimes /* 439df8bae1dSRodney W. Grimes * Restrict application to use a buffer the same size as 440df8bae1dSRodney W. Grimes * as kernel buffers. 441df8bae1dSRodney W. Grimes */ 442df8bae1dSRodney W. Grimes if (uio->uio_resid != d->bd_bufsize) 443df8bae1dSRodney W. Grimes return (EINVAL); 444df8bae1dSRodney W. Grimes 445df8bae1dSRodney W. Grimes s = splimp(); 446df8bae1dSRodney W. Grimes /* 447df8bae1dSRodney W. Grimes * If the hold buffer is empty, then do a timed sleep, which 448df8bae1dSRodney W. Grimes * ends when the timeout expires or when enough packets 449df8bae1dSRodney W. Grimes * have arrived to fill the store buffer. 450df8bae1dSRodney W. Grimes */ 451df8bae1dSRodney W. Grimes while (d->bd_hbuf == 0) { 452df8bae1dSRodney W. Grimes if (d->bd_immediate && d->bd_slen != 0) { 453df8bae1dSRodney W. Grimes /* 454df8bae1dSRodney W. Grimes * A packet(s) either arrived since the previous 455df8bae1dSRodney W. Grimes * read or arrived while we were asleep. 456df8bae1dSRodney W. Grimes * Rotate the buffers and return what's here. 457df8bae1dSRodney W. Grimes */ 458df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 459df8bae1dSRodney W. Grimes break; 460df8bae1dSRodney W. Grimes } 46100a83887SPaul Traina if (d->bd_rtout != -1) 462df8bae1dSRodney W. Grimes error = BPF_SLEEP((caddr_t)d, PRINET|PCATCH, "bpf", 463df8bae1dSRodney W. Grimes d->bd_rtout); 46400a83887SPaul Traina else 46500a83887SPaul Traina error = EWOULDBLOCK; /* User requested non-blocking I/O */ 466df8bae1dSRodney W. Grimes if (error == EINTR || error == ERESTART) { 467df8bae1dSRodney W. Grimes splx(s); 468df8bae1dSRodney W. Grimes return (error); 469df8bae1dSRodney W. Grimes } 470df8bae1dSRodney W. Grimes if (error == EWOULDBLOCK) { 471df8bae1dSRodney W. Grimes /* 472df8bae1dSRodney W. Grimes * On a timeout, return what's in the buffer, 473df8bae1dSRodney W. Grimes * which may be nothing. If there is something 474df8bae1dSRodney W. Grimes * in the store buffer, we can rotate the buffers. 475df8bae1dSRodney W. Grimes */ 476df8bae1dSRodney W. Grimes if (d->bd_hbuf) 477df8bae1dSRodney W. Grimes /* 478df8bae1dSRodney W. Grimes * We filled up the buffer in between 479df8bae1dSRodney W. Grimes * getting the timeout and arriving 480df8bae1dSRodney W. Grimes * here, so we don't need to rotate. 481df8bae1dSRodney W. Grimes */ 482df8bae1dSRodney W. Grimes break; 483df8bae1dSRodney W. Grimes 484df8bae1dSRodney W. Grimes if (d->bd_slen == 0) { 485df8bae1dSRodney W. Grimes splx(s); 486df8bae1dSRodney W. Grimes return (0); 487df8bae1dSRodney W. Grimes } 488df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 489df8bae1dSRodney W. Grimes break; 490df8bae1dSRodney W. Grimes } 491df8bae1dSRodney W. Grimes } 492df8bae1dSRodney W. Grimes /* 493df8bae1dSRodney W. Grimes * At this point, we know we have something in the hold slot. 494df8bae1dSRodney W. Grimes */ 495df8bae1dSRodney W. Grimes splx(s); 496df8bae1dSRodney W. Grimes 497df8bae1dSRodney W. Grimes /* 498df8bae1dSRodney W. Grimes * Move data from hold buffer into user space. 499df8bae1dSRodney W. Grimes * We know the entire buffer is transferred since 500df8bae1dSRodney W. Grimes * we checked above that the read buffer is bpf_bufsize bytes. 501df8bae1dSRodney W. Grimes */ 502df8bae1dSRodney W. Grimes error = UIOMOVE(d->bd_hbuf, d->bd_hlen, UIO_READ, uio); 503df8bae1dSRodney W. Grimes 504df8bae1dSRodney W. Grimes s = splimp(); 505df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 506df8bae1dSRodney W. Grimes d->bd_hbuf = 0; 507df8bae1dSRodney W. Grimes d->bd_hlen = 0; 508df8bae1dSRodney W. Grimes splx(s); 509df8bae1dSRodney W. Grimes 510df8bae1dSRodney W. Grimes return (error); 511df8bae1dSRodney W. Grimes } 512df8bae1dSRodney W. Grimes 513df8bae1dSRodney W. Grimes 514df8bae1dSRodney W. Grimes /* 515df8bae1dSRodney W. Grimes * If there are processes sleeping on this descriptor, wake them up. 516df8bae1dSRodney W. Grimes */ 517df8bae1dSRodney W. Grimes static inline void 518df8bae1dSRodney W. Grimes bpf_wakeup(d) 519df8bae1dSRodney W. Grimes register struct bpf_d *d; 520df8bae1dSRodney W. Grimes { 52100a83887SPaul Traina struct proc *p; 52200a83887SPaul Traina 523df8bae1dSRodney W. Grimes wakeup((caddr_t)d); 52400a83887SPaul Traina if (d->bd_async && d->bd_sig) 52500a83887SPaul Traina if (d->bd_pgid > 0) 52600a83887SPaul Traina gsignal (d->bd_pgid, d->bd_sig); 52700a83887SPaul Traina else if (p = pfind (-d->bd_pgid)) 52800a83887SPaul Traina psignal (p, d->bd_sig); 52900a83887SPaul Traina 530df8bae1dSRodney W. Grimes #if BSD >= 199103 531df8bae1dSRodney W. Grimes selwakeup(&d->bd_sel); 532df8bae1dSRodney W. Grimes /* XXX */ 533df8bae1dSRodney W. Grimes d->bd_sel.si_pid = 0; 534df8bae1dSRodney W. Grimes #else 535df8bae1dSRodney W. Grimes if (d->bd_selproc) { 536df8bae1dSRodney W. Grimes selwakeup(d->bd_selproc, (int)d->bd_selcoll); 537df8bae1dSRodney W. Grimes d->bd_selcoll = 0; 538df8bae1dSRodney W. Grimes d->bd_selproc = 0; 539df8bae1dSRodney W. Grimes } 540df8bae1dSRodney W. Grimes #endif 541df8bae1dSRodney W. Grimes } 542df8bae1dSRodney W. Grimes 543df8bae1dSRodney W. Grimes int 54460039670SBruce Evans bpfwrite(dev, uio, ioflag) 545df8bae1dSRodney W. Grimes dev_t dev; 546df8bae1dSRodney W. Grimes struct uio *uio; 54760039670SBruce Evans int ioflag; 548df8bae1dSRodney W. Grimes { 549df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 550df8bae1dSRodney W. Grimes struct ifnet *ifp; 551df8bae1dSRodney W. Grimes struct mbuf *m; 552df8bae1dSRodney W. Grimes int error, s; 553df8bae1dSRodney W. Grimes static struct sockaddr dst; 554df8bae1dSRodney W. Grimes int datlen; 555df8bae1dSRodney W. Grimes 556df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 557df8bae1dSRodney W. Grimes return (ENXIO); 558df8bae1dSRodney W. Grimes 559df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 560df8bae1dSRodney W. Grimes 561df8bae1dSRodney W. Grimes if (uio->uio_resid == 0) 562df8bae1dSRodney W. Grimes return (0); 563df8bae1dSRodney W. Grimes 564df8bae1dSRodney W. Grimes error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, &datlen); 565df8bae1dSRodney W. Grimes if (error) 566df8bae1dSRodney W. Grimes return (error); 567df8bae1dSRodney W. Grimes 568df8bae1dSRodney W. Grimes if (datlen > ifp->if_mtu) 569df8bae1dSRodney W. Grimes return (EMSGSIZE); 570df8bae1dSRodney W. Grimes 571df8bae1dSRodney W. Grimes s = splnet(); 572df8bae1dSRodney W. Grimes #if BSD >= 199103 573df8bae1dSRodney W. Grimes error = (*ifp->if_output)(ifp, m, &dst, (struct rtentry *)0); 574df8bae1dSRodney W. Grimes #else 575df8bae1dSRodney W. Grimes error = (*ifp->if_output)(ifp, m, &dst); 576df8bae1dSRodney W. Grimes #endif 577df8bae1dSRodney W. Grimes splx(s); 578df8bae1dSRodney W. Grimes /* 579df8bae1dSRodney W. Grimes * The driver frees the mbuf. 580df8bae1dSRodney W. Grimes */ 581df8bae1dSRodney W. Grimes return (error); 582df8bae1dSRodney W. Grimes } 583df8bae1dSRodney W. Grimes 584df8bae1dSRodney W. Grimes /* 585df8bae1dSRodney W. Grimes * Reset a descriptor by flushing its packet buffer and clearing the 586df8bae1dSRodney W. Grimes * receive and drop counts. Should be called at splimp. 587df8bae1dSRodney W. Grimes */ 588df8bae1dSRodney W. Grimes static void 589df8bae1dSRodney W. Grimes reset_d(d) 590df8bae1dSRodney W. Grimes struct bpf_d *d; 591df8bae1dSRodney W. Grimes { 592df8bae1dSRodney W. Grimes if (d->bd_hbuf) { 593df8bae1dSRodney W. Grimes /* Free the hold buffer. */ 594df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 595df8bae1dSRodney W. Grimes d->bd_hbuf = 0; 596df8bae1dSRodney W. Grimes } 597df8bae1dSRodney W. Grimes d->bd_slen = 0; 598df8bae1dSRodney W. Grimes d->bd_hlen = 0; 599df8bae1dSRodney W. Grimes d->bd_rcount = 0; 600df8bae1dSRodney W. Grimes d->bd_dcount = 0; 601df8bae1dSRodney W. Grimes } 602df8bae1dSRodney W. Grimes 603df8bae1dSRodney W. Grimes /* 604df8bae1dSRodney W. Grimes * FIONREAD Check for read packet available. 605df8bae1dSRodney W. Grimes * SIOCGIFADDR Get interface address - convenient hook to driver. 606df8bae1dSRodney W. Grimes * BIOCGBLEN Get buffer len [for read()]. 607df8bae1dSRodney W. Grimes * BIOCSETF Set ethernet read filter. 608df8bae1dSRodney W. Grimes * BIOCFLUSH Flush read packet buffer. 609df8bae1dSRodney W. Grimes * BIOCPROMISC Put interface into promiscuous mode. 610df8bae1dSRodney W. Grimes * BIOCGDLT Get link layer type. 611df8bae1dSRodney W. Grimes * BIOCGETIF Get interface name. 612df8bae1dSRodney W. Grimes * BIOCSETIF Set interface. 613df8bae1dSRodney W. Grimes * BIOCSRTIMEOUT Set read timeout. 614df8bae1dSRodney W. Grimes * BIOCGRTIMEOUT Get read timeout. 615df8bae1dSRodney W. Grimes * BIOCGSTATS Get packet stats. 616df8bae1dSRodney W. Grimes * BIOCIMMEDIATE Set immediate mode. 617df8bae1dSRodney W. Grimes * BIOCVERSION Get filter language version. 618df8bae1dSRodney W. Grimes */ 619df8bae1dSRodney W. Grimes /* ARGSUSED */ 620df8bae1dSRodney W. Grimes int 62160039670SBruce Evans bpfioctl(dev, cmd, addr, flags, p) 622df8bae1dSRodney W. Grimes dev_t dev; 623df8bae1dSRodney W. Grimes int cmd; 624df8bae1dSRodney W. Grimes caddr_t addr; 62560039670SBruce Evans int flags; 62660039670SBruce Evans struct proc *p; 627df8bae1dSRodney W. Grimes { 628df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 629df8bae1dSRodney W. Grimes int s, error = 0; 630df8bae1dSRodney W. Grimes 631df8bae1dSRodney W. Grimes switch (cmd) { 632df8bae1dSRodney W. Grimes 633df8bae1dSRodney W. Grimes default: 634df8bae1dSRodney W. Grimes error = EINVAL; 635df8bae1dSRodney W. Grimes break; 636df8bae1dSRodney W. Grimes 637df8bae1dSRodney W. Grimes /* 638df8bae1dSRodney W. Grimes * Check for read packet available. 639df8bae1dSRodney W. Grimes */ 640df8bae1dSRodney W. Grimes case FIONREAD: 641df8bae1dSRodney W. Grimes { 642df8bae1dSRodney W. Grimes int n; 643df8bae1dSRodney W. Grimes 644df8bae1dSRodney W. Grimes s = splimp(); 645df8bae1dSRodney W. Grimes n = d->bd_slen; 646df8bae1dSRodney W. Grimes if (d->bd_hbuf) 647df8bae1dSRodney W. Grimes n += d->bd_hlen; 648df8bae1dSRodney W. Grimes splx(s); 649df8bae1dSRodney W. Grimes 650df8bae1dSRodney W. Grimes *(int *)addr = n; 651df8bae1dSRodney W. Grimes break; 652df8bae1dSRodney W. Grimes } 653df8bae1dSRodney W. Grimes 654df8bae1dSRodney W. Grimes case SIOCGIFADDR: 655df8bae1dSRodney W. Grimes { 656df8bae1dSRodney W. Grimes struct ifnet *ifp; 657df8bae1dSRodney W. Grimes 658df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 659df8bae1dSRodney W. Grimes error = EINVAL; 660df8bae1dSRodney W. Grimes else { 661df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 662df8bae1dSRodney W. Grimes error = (*ifp->if_ioctl)(ifp, cmd, addr); 663df8bae1dSRodney W. Grimes } 664df8bae1dSRodney W. Grimes break; 665df8bae1dSRodney W. Grimes } 666df8bae1dSRodney W. Grimes 667df8bae1dSRodney W. Grimes /* 668df8bae1dSRodney W. Grimes * Get buffer len [for read()]. 669df8bae1dSRodney W. Grimes */ 670df8bae1dSRodney W. Grimes case BIOCGBLEN: 671df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bufsize; 672df8bae1dSRodney W. Grimes break; 673df8bae1dSRodney W. Grimes 674df8bae1dSRodney W. Grimes /* 675df8bae1dSRodney W. Grimes * Set buffer length. 676df8bae1dSRodney W. Grimes */ 677df8bae1dSRodney W. Grimes case BIOCSBLEN: 678df8bae1dSRodney W. Grimes #if BSD < 199103 679df8bae1dSRodney W. Grimes error = EINVAL; 680df8bae1dSRodney W. Grimes #else 681df8bae1dSRodney W. Grimes if (d->bd_bif != 0) 682df8bae1dSRodney W. Grimes error = EINVAL; 683df8bae1dSRodney W. Grimes else { 684df8bae1dSRodney W. Grimes register u_int size = *(u_int *)addr; 685df8bae1dSRodney W. Grimes 686df8bae1dSRodney W. Grimes if (size > BPF_MAXBUFSIZE) 687df8bae1dSRodney W. Grimes *(u_int *)addr = size = BPF_MAXBUFSIZE; 688df8bae1dSRodney W. Grimes else if (size < BPF_MINBUFSIZE) 689df8bae1dSRodney W. Grimes *(u_int *)addr = size = BPF_MINBUFSIZE; 690df8bae1dSRodney W. Grimes d->bd_bufsize = size; 691df8bae1dSRodney W. Grimes } 692df8bae1dSRodney W. Grimes #endif 693df8bae1dSRodney W. Grimes break; 694df8bae1dSRodney W. Grimes 695df8bae1dSRodney W. Grimes /* 696df8bae1dSRodney W. Grimes * Set link layer read filter. 697df8bae1dSRodney W. Grimes */ 698df8bae1dSRodney W. Grimes case BIOCSETF: 699df8bae1dSRodney W. Grimes error = bpf_setf(d, (struct bpf_program *)addr); 700df8bae1dSRodney W. Grimes break; 701df8bae1dSRodney W. Grimes 702df8bae1dSRodney W. Grimes /* 703df8bae1dSRodney W. Grimes * Flush read packet buffer. 704df8bae1dSRodney W. Grimes */ 705df8bae1dSRodney W. Grimes case BIOCFLUSH: 706df8bae1dSRodney W. Grimes s = splimp(); 707df8bae1dSRodney W. Grimes reset_d(d); 708df8bae1dSRodney W. Grimes splx(s); 709df8bae1dSRodney W. Grimes break; 710df8bae1dSRodney W. Grimes 711df8bae1dSRodney W. Grimes /* 712df8bae1dSRodney W. Grimes * Put interface into promiscuous mode. 713df8bae1dSRodney W. Grimes */ 714df8bae1dSRodney W. Grimes case BIOCPROMISC: 715df8bae1dSRodney W. Grimes if (d->bd_bif == 0) { 716df8bae1dSRodney W. Grimes /* 717df8bae1dSRodney W. Grimes * No interface attached yet. 718df8bae1dSRodney W. Grimes */ 719df8bae1dSRodney W. Grimes error = EINVAL; 720df8bae1dSRodney W. Grimes break; 721df8bae1dSRodney W. Grimes } 722df8bae1dSRodney W. Grimes s = splimp(); 723df8bae1dSRodney W. Grimes if (d->bd_promisc == 0) { 724df8bae1dSRodney W. Grimes error = ifpromisc(d->bd_bif->bif_ifp, 1); 725df8bae1dSRodney W. Grimes if (error == 0) 726df8bae1dSRodney W. Grimes d->bd_promisc = 1; 727df8bae1dSRodney W. Grimes } 728df8bae1dSRodney W. Grimes splx(s); 729df8bae1dSRodney W. Grimes break; 730df8bae1dSRodney W. Grimes 731df8bae1dSRodney W. Grimes /* 732df8bae1dSRodney W. Grimes * Get device parameters. 733df8bae1dSRodney W. Grimes */ 734df8bae1dSRodney W. Grimes case BIOCGDLT: 735df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 736df8bae1dSRodney W. Grimes error = EINVAL; 737df8bae1dSRodney W. Grimes else 738df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bif->bif_dlt; 739df8bae1dSRodney W. Grimes break; 740df8bae1dSRodney W. Grimes 741df8bae1dSRodney W. Grimes /* 742df8bae1dSRodney W. Grimes * Set interface name. 743df8bae1dSRodney W. Grimes */ 744df8bae1dSRodney W. Grimes case BIOCGETIF: 745df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 746df8bae1dSRodney W. Grimes error = EINVAL; 747df8bae1dSRodney W. Grimes else 748df8bae1dSRodney W. Grimes bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr); 749df8bae1dSRodney W. Grimes break; 750df8bae1dSRodney W. Grimes 751df8bae1dSRodney W. Grimes /* 752df8bae1dSRodney W. Grimes * Set interface. 753df8bae1dSRodney W. Grimes */ 754df8bae1dSRodney W. Grimes case BIOCSETIF: 755df8bae1dSRodney W. Grimes error = bpf_setif(d, (struct ifreq *)addr); 756df8bae1dSRodney W. Grimes break; 757df8bae1dSRodney W. Grimes 758df8bae1dSRodney W. Grimes /* 759df8bae1dSRodney W. Grimes * Set read timeout. 760df8bae1dSRodney W. Grimes */ 761df8bae1dSRodney W. Grimes case BIOCSRTIMEOUT: 762df8bae1dSRodney W. Grimes { 763df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 764df8bae1dSRodney W. Grimes u_long msec; 765df8bae1dSRodney W. Grimes 766df8bae1dSRodney W. Grimes /* Compute number of milliseconds. */ 767df8bae1dSRodney W. Grimes msec = tv->tv_sec * 1000 + tv->tv_usec / 1000; 768df8bae1dSRodney W. Grimes /* Scale milliseconds to ticks. Assume hard 769df8bae1dSRodney W. Grimes clock has millisecond or greater resolution 770df8bae1dSRodney W. Grimes (i.e. tick >= 1000). For 10ms hardclock, 771df8bae1dSRodney W. Grimes tick/1000 = 10, so rtout<-msec/10. */ 772df8bae1dSRodney W. Grimes d->bd_rtout = msec / (tick / 1000); 773df8bae1dSRodney W. Grimes break; 774df8bae1dSRodney W. Grimes } 775df8bae1dSRodney W. Grimes 776df8bae1dSRodney W. Grimes /* 777df8bae1dSRodney W. Grimes * Get read timeout. 778df8bae1dSRodney W. Grimes */ 779df8bae1dSRodney W. Grimes case BIOCGRTIMEOUT: 780df8bae1dSRodney W. Grimes { 781df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 782df8bae1dSRodney W. Grimes u_long msec = d->bd_rtout; 783df8bae1dSRodney W. Grimes 784df8bae1dSRodney W. Grimes msec *= tick / 1000; 785df8bae1dSRodney W. Grimes tv->tv_sec = msec / 1000; 786df8bae1dSRodney W. Grimes tv->tv_usec = msec % 1000; 787df8bae1dSRodney W. Grimes break; 788df8bae1dSRodney W. Grimes } 789df8bae1dSRodney W. Grimes 790df8bae1dSRodney W. Grimes /* 791df8bae1dSRodney W. Grimes * Get packet stats. 792df8bae1dSRodney W. Grimes */ 793df8bae1dSRodney W. Grimes case BIOCGSTATS: 794df8bae1dSRodney W. Grimes { 795df8bae1dSRodney W. Grimes struct bpf_stat *bs = (struct bpf_stat *)addr; 796df8bae1dSRodney W. Grimes 797df8bae1dSRodney W. Grimes bs->bs_recv = d->bd_rcount; 798df8bae1dSRodney W. Grimes bs->bs_drop = d->bd_dcount; 799df8bae1dSRodney W. Grimes break; 800df8bae1dSRodney W. Grimes } 801df8bae1dSRodney W. Grimes 802df8bae1dSRodney W. Grimes /* 803df8bae1dSRodney W. Grimes * Set immediate mode. 804df8bae1dSRodney W. Grimes */ 805df8bae1dSRodney W. Grimes case BIOCIMMEDIATE: 806df8bae1dSRodney W. Grimes d->bd_immediate = *(u_int *)addr; 807df8bae1dSRodney W. Grimes break; 808df8bae1dSRodney W. Grimes 809df8bae1dSRodney W. Grimes case BIOCVERSION: 810df8bae1dSRodney W. Grimes { 811df8bae1dSRodney W. Grimes struct bpf_version *bv = (struct bpf_version *)addr; 812df8bae1dSRodney W. Grimes 813df8bae1dSRodney W. Grimes bv->bv_major = BPF_MAJOR_VERSION; 814df8bae1dSRodney W. Grimes bv->bv_minor = BPF_MINOR_VERSION; 815df8bae1dSRodney W. Grimes break; 816df8bae1dSRodney W. Grimes } 81700a83887SPaul Traina 81800a83887SPaul Traina 81900a83887SPaul Traina case FIONBIO: /* Non-blocking I/O */ 82000a83887SPaul Traina if (*(int *)addr) 82100a83887SPaul Traina d->bd_rtout = -1; 82200a83887SPaul Traina else 82300a83887SPaul Traina d->bd_rtout = 0; 82400a83887SPaul Traina break; 82500a83887SPaul Traina 82600a83887SPaul Traina case FIOASYNC: /* Send signal on receive packets */ 82700a83887SPaul Traina d->bd_async = *(int *)addr; 82800a83887SPaul Traina break; 82900a83887SPaul Traina 83000a83887SPaul Traina /* N.B. ioctl (FIOSETOWN) and fcntl (F_SETOWN) both end up doing the 83100a83887SPaul Traina equivalent of a TIOCSPGRP and hence end up here. *However* TIOCSPGRP's arg 83200a83887SPaul Traina is a process group if it's positive and a process id if it's negative. This 83300a83887SPaul Traina is exactly the opposite of what the other two functions want! Therefore 83400a83887SPaul Traina there is code in ioctl and fcntl to negate the arg before calling here. */ 83500a83887SPaul Traina 83600a83887SPaul Traina case TIOCSPGRP: /* Process or group to send signals to */ 83700a83887SPaul Traina d->bd_pgid = *(int *)addr; 83800a83887SPaul Traina break; 83900a83887SPaul Traina 84000a83887SPaul Traina case TIOCGPGRP: 84100a83887SPaul Traina *(int *)addr = d->bd_pgid; 84200a83887SPaul Traina break; 84300a83887SPaul Traina 84400a83887SPaul Traina case BIOCSRSIG: /* Set receive signal */ 84500a83887SPaul Traina { 84600a83887SPaul Traina u_int sig; 84700a83887SPaul Traina 84800a83887SPaul Traina sig = *(u_int *)addr; 84900a83887SPaul Traina 85000a83887SPaul Traina if (sig >= NSIG) 85100a83887SPaul Traina error = EINVAL; 85200a83887SPaul Traina else 85300a83887SPaul Traina d->bd_sig = sig; 85400a83887SPaul Traina break; 85500a83887SPaul Traina } 85600a83887SPaul Traina case BIOCGRSIG: 85700a83887SPaul Traina *(u_int *)addr = d->bd_sig; 85800a83887SPaul Traina break; 859df8bae1dSRodney W. Grimes } 860df8bae1dSRodney W. Grimes return (error); 861df8bae1dSRodney W. Grimes } 862df8bae1dSRodney W. Grimes 863df8bae1dSRodney W. Grimes /* 864df8bae1dSRodney W. Grimes * Set d's packet filter program to fp. If this file already has a filter, 865df8bae1dSRodney W. Grimes * free it and replace it. Returns EINVAL for bogus requests. 866df8bae1dSRodney W. Grimes */ 867df8bae1dSRodney W. Grimes int 868df8bae1dSRodney W. Grimes bpf_setf(d, fp) 869df8bae1dSRodney W. Grimes struct bpf_d *d; 870df8bae1dSRodney W. Grimes struct bpf_program *fp; 871df8bae1dSRodney W. Grimes { 872df8bae1dSRodney W. Grimes struct bpf_insn *fcode, *old; 873df8bae1dSRodney W. Grimes u_int flen, size; 874df8bae1dSRodney W. Grimes int s; 875df8bae1dSRodney W. Grimes 876df8bae1dSRodney W. Grimes old = d->bd_filter; 877df8bae1dSRodney W. Grimes if (fp->bf_insns == 0) { 878df8bae1dSRodney W. Grimes if (fp->bf_len != 0) 879df8bae1dSRodney W. Grimes return (EINVAL); 880df8bae1dSRodney W. Grimes s = splimp(); 881df8bae1dSRodney W. Grimes d->bd_filter = 0; 882df8bae1dSRodney W. Grimes reset_d(d); 883df8bae1dSRodney W. Grimes splx(s); 884df8bae1dSRodney W. Grimes if (old != 0) 885df8bae1dSRodney W. Grimes free((caddr_t)old, M_DEVBUF); 886df8bae1dSRodney W. Grimes return (0); 887df8bae1dSRodney W. Grimes } 888df8bae1dSRodney W. Grimes flen = fp->bf_len; 889df8bae1dSRodney W. Grimes if (flen > BPF_MAXINSNS) 890df8bae1dSRodney W. Grimes return (EINVAL); 891df8bae1dSRodney W. Grimes 892df8bae1dSRodney W. Grimes size = flen * sizeof(*fp->bf_insns); 893df8bae1dSRodney W. Grimes fcode = (struct bpf_insn *)malloc(size, M_DEVBUF, M_WAITOK); 894df8bae1dSRodney W. Grimes if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && 895df8bae1dSRodney W. Grimes bpf_validate(fcode, (int)flen)) { 896df8bae1dSRodney W. Grimes s = splimp(); 897df8bae1dSRodney W. Grimes d->bd_filter = fcode; 898df8bae1dSRodney W. Grimes reset_d(d); 899df8bae1dSRodney W. Grimes splx(s); 900df8bae1dSRodney W. Grimes if (old != 0) 901df8bae1dSRodney W. Grimes free((caddr_t)old, M_DEVBUF); 902df8bae1dSRodney W. Grimes 903df8bae1dSRodney W. Grimes return (0); 904df8bae1dSRodney W. Grimes } 905df8bae1dSRodney W. Grimes free((caddr_t)fcode, M_DEVBUF); 906df8bae1dSRodney W. Grimes return (EINVAL); 907df8bae1dSRodney W. Grimes } 908df8bae1dSRodney W. Grimes 909df8bae1dSRodney W. Grimes /* 910df8bae1dSRodney W. Grimes * Detach a file from its current interface (if attached at all) and attach 911df8bae1dSRodney W. Grimes * to the interface indicated by the name stored in ifr. 912df8bae1dSRodney W. Grimes * Return an errno or 0. 913df8bae1dSRodney W. Grimes */ 914df8bae1dSRodney W. Grimes static int 915df8bae1dSRodney W. Grimes bpf_setif(d, ifr) 916df8bae1dSRodney W. Grimes struct bpf_d *d; 917df8bae1dSRodney W. Grimes struct ifreq *ifr; 918df8bae1dSRodney W. Grimes { 919df8bae1dSRodney W. Grimes struct bpf_if *bp; 920df8bae1dSRodney W. Grimes char *cp; 921df8bae1dSRodney W. Grimes int unit, s, error; 922df8bae1dSRodney W. Grimes 923df8bae1dSRodney W. Grimes /* 924df8bae1dSRodney W. Grimes * Separate string into name part and unit number. Put a null 925df8bae1dSRodney W. Grimes * byte at the end of the name part, and compute the number. 926df8bae1dSRodney W. Grimes * If the a unit number is unspecified, the default is 0, 927df8bae1dSRodney W. Grimes * as initialized above. XXX This should be common code. 928df8bae1dSRodney W. Grimes */ 929df8bae1dSRodney W. Grimes unit = 0; 930df8bae1dSRodney W. Grimes cp = ifr->ifr_name; 931df8bae1dSRodney W. Grimes cp[sizeof(ifr->ifr_name) - 1] = '\0'; 932df8bae1dSRodney W. Grimes while (*cp++) { 933df8bae1dSRodney W. Grimes if (*cp >= '0' && *cp <= '9') { 934df8bae1dSRodney W. Grimes unit = *cp - '0'; 935df8bae1dSRodney W. Grimes *cp++ = '\0'; 936df8bae1dSRodney W. Grimes while (*cp) 937df8bae1dSRodney W. Grimes unit = 10 * unit + *cp++ - '0'; 938df8bae1dSRodney W. Grimes break; 939df8bae1dSRodney W. Grimes } 940df8bae1dSRodney W. Grimes } 941df8bae1dSRodney W. Grimes /* 942df8bae1dSRodney W. Grimes * Look through attached interfaces for the named one. 943df8bae1dSRodney W. Grimes */ 944df8bae1dSRodney W. Grimes for (bp = bpf_iflist; bp != 0; bp = bp->bif_next) { 945df8bae1dSRodney W. Grimes struct ifnet *ifp = bp->bif_ifp; 946df8bae1dSRodney W. Grimes 947df8bae1dSRodney W. Grimes if (ifp == 0 || unit != ifp->if_unit 948df8bae1dSRodney W. Grimes || strcmp(ifp->if_name, ifr->ifr_name) != 0) 949df8bae1dSRodney W. Grimes continue; 950df8bae1dSRodney W. Grimes /* 951df8bae1dSRodney W. Grimes * We found the requested interface. 952df8bae1dSRodney W. Grimes * If it's not up, return an error. 953df8bae1dSRodney W. Grimes * Allocate the packet buffers if we need to. 954df8bae1dSRodney W. Grimes * If we're already attached to requested interface, 955df8bae1dSRodney W. Grimes * just flush the buffer. 956df8bae1dSRodney W. Grimes */ 957df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_UP) == 0) 958df8bae1dSRodney W. Grimes return (ENETDOWN); 959df8bae1dSRodney W. Grimes 960df8bae1dSRodney W. Grimes if (d->bd_sbuf == 0) { 961df8bae1dSRodney W. Grimes error = bpf_allocbufs(d); 962df8bae1dSRodney W. Grimes if (error != 0) 963df8bae1dSRodney W. Grimes return (error); 964df8bae1dSRodney W. Grimes } 965df8bae1dSRodney W. Grimes s = splimp(); 966df8bae1dSRodney W. Grimes if (bp != d->bd_bif) { 967df8bae1dSRodney W. Grimes if (d->bd_bif) 968df8bae1dSRodney W. Grimes /* 969df8bae1dSRodney W. Grimes * Detach if attached to something else. 970df8bae1dSRodney W. Grimes */ 971df8bae1dSRodney W. Grimes bpf_detachd(d); 972df8bae1dSRodney W. Grimes 973df8bae1dSRodney W. Grimes bpf_attachd(d, bp); 974df8bae1dSRodney W. Grimes } 975df8bae1dSRodney W. Grimes reset_d(d); 976df8bae1dSRodney W. Grimes splx(s); 977df8bae1dSRodney W. Grimes return (0); 978df8bae1dSRodney W. Grimes } 979df8bae1dSRodney W. Grimes /* Not found. */ 980df8bae1dSRodney W. Grimes return (ENXIO); 981df8bae1dSRodney W. Grimes } 982df8bae1dSRodney W. Grimes 983df8bae1dSRodney W. Grimes /* 984df8bae1dSRodney W. Grimes * Convert an interface name plus unit number of an ifp to a single 985df8bae1dSRodney W. Grimes * name which is returned in the ifr. 986df8bae1dSRodney W. Grimes */ 987df8bae1dSRodney W. Grimes static void 988df8bae1dSRodney W. Grimes bpf_ifname(ifp, ifr) 989df8bae1dSRodney W. Grimes struct ifnet *ifp; 990df8bae1dSRodney W. Grimes struct ifreq *ifr; 991df8bae1dSRodney W. Grimes { 992df8bae1dSRodney W. Grimes char *s = ifp->if_name; 993df8bae1dSRodney W. Grimes char *d = ifr->ifr_name; 994df8bae1dSRodney W. Grimes 995df8bae1dSRodney W. Grimes while (*d++ = *s++) 996df8bae1dSRodney W. Grimes continue; 997df8bae1dSRodney W. Grimes /* XXX Assume that unit number is less than 10. */ 998df8bae1dSRodney W. Grimes *d++ = ifp->if_unit + '0'; 999df8bae1dSRodney W. Grimes *d = '\0'; 1000df8bae1dSRodney W. Grimes } 1001df8bae1dSRodney W. Grimes 1002df8bae1dSRodney W. Grimes /* 1003df8bae1dSRodney W. Grimes * The new select interface passes down the proc pointer; the old select 1004df8bae1dSRodney W. Grimes * stubs had to grab it out of the user struct. This glue allows either case. 1005df8bae1dSRodney W. Grimes */ 1006df8bae1dSRodney W. Grimes #if BSD >= 199103 1007df8bae1dSRodney W. Grimes #define bpf_select bpfselect 1008df8bae1dSRodney W. Grimes #else 1009df8bae1dSRodney W. Grimes int 1010df8bae1dSRodney W. Grimes bpfselect(dev, rw) 1011df8bae1dSRodney W. Grimes register dev_t dev; 1012df8bae1dSRodney W. Grimes int rw; 1013df8bae1dSRodney W. Grimes { 1014df8bae1dSRodney W. Grimes return (bpf_select(dev, rw, u.u_procp)); 1015df8bae1dSRodney W. Grimes } 1016df8bae1dSRodney W. Grimes #endif 1017df8bae1dSRodney W. Grimes 1018df8bae1dSRodney W. Grimes /* 1019df8bae1dSRodney W. Grimes * Support for select() system call 1020df8bae1dSRodney W. Grimes * 1021df8bae1dSRodney W. Grimes * Return true iff the specific operation will not block indefinitely. 1022df8bae1dSRodney W. Grimes * Otherwise, return false but make a note that a selwakeup() must be done. 1023df8bae1dSRodney W. Grimes */ 1024df8bae1dSRodney W. Grimes int 1025df8bae1dSRodney W. Grimes bpf_select(dev, rw, p) 1026df8bae1dSRodney W. Grimes register dev_t dev; 1027df8bae1dSRodney W. Grimes int rw; 1028df8bae1dSRodney W. Grimes struct proc *p; 1029df8bae1dSRodney W. Grimes { 1030df8bae1dSRodney W. Grimes register struct bpf_d *d; 1031df8bae1dSRodney W. Grimes register int s; 1032df8bae1dSRodney W. Grimes 1033df8bae1dSRodney W. Grimes if (rw != FREAD) 1034df8bae1dSRodney W. Grimes return (0); 1035df8bae1dSRodney W. Grimes /* 1036df8bae1dSRodney W. Grimes * An imitation of the FIONREAD ioctl code. 1037df8bae1dSRodney W. Grimes */ 1038df8bae1dSRodney W. Grimes d = &bpf_dtab[minor(dev)]; 1039df8bae1dSRodney W. Grimes 1040df8bae1dSRodney W. Grimes s = splimp(); 1041df8bae1dSRodney W. Grimes if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0)) { 1042df8bae1dSRodney W. Grimes /* 1043df8bae1dSRodney W. Grimes * There is data waiting. 1044df8bae1dSRodney W. Grimes */ 1045df8bae1dSRodney W. Grimes splx(s); 1046df8bae1dSRodney W. Grimes return (1); 1047df8bae1dSRodney W. Grimes } 1048df8bae1dSRodney W. Grimes #if BSD >= 199103 1049df8bae1dSRodney W. Grimes selrecord(p, &d->bd_sel); 1050df8bae1dSRodney W. Grimes #else 1051df8bae1dSRodney W. Grimes /* 1052df8bae1dSRodney W. Grimes * No data ready. If there's already a select() waiting on this 1053df8bae1dSRodney W. Grimes * minor device then this is a collision. This shouldn't happen 1054df8bae1dSRodney W. Grimes * because minors really should not be shared, but if a process 1055df8bae1dSRodney W. Grimes * forks while one of these is open, it is possible that both 1056df8bae1dSRodney W. Grimes * processes could select on the same descriptor. 1057df8bae1dSRodney W. Grimes */ 1058df8bae1dSRodney W. Grimes if (d->bd_selproc && d->bd_selproc->p_wchan == (caddr_t)&selwait) 1059df8bae1dSRodney W. Grimes d->bd_selcoll = 1; 1060df8bae1dSRodney W. Grimes else 1061df8bae1dSRodney W. Grimes d->bd_selproc = p; 1062df8bae1dSRodney W. Grimes #endif 1063df8bae1dSRodney W. Grimes splx(s); 1064df8bae1dSRodney W. Grimes return (0); 1065df8bae1dSRodney W. Grimes } 1066df8bae1dSRodney W. Grimes 1067df8bae1dSRodney W. Grimes /* 1068df8bae1dSRodney W. Grimes * Incoming linkage from device drivers. Process the packet pkt, of length 1069df8bae1dSRodney W. Grimes * pktlen, which is stored in a contiguous buffer. The packet is parsed 1070df8bae1dSRodney W. Grimes * by each process' filter, and if accepted, stashed into the corresponding 1071df8bae1dSRodney W. Grimes * buffer. 1072df8bae1dSRodney W. Grimes */ 1073df8bae1dSRodney W. Grimes void 1074df8bae1dSRodney W. Grimes bpf_tap(arg, pkt, pktlen) 1075df8bae1dSRodney W. Grimes caddr_t arg; 1076df8bae1dSRodney W. Grimes register u_char *pkt; 1077df8bae1dSRodney W. Grimes register u_int pktlen; 1078df8bae1dSRodney W. Grimes { 1079df8bae1dSRodney W. Grimes struct bpf_if *bp; 1080df8bae1dSRodney W. Grimes register struct bpf_d *d; 1081df8bae1dSRodney W. Grimes register u_int slen; 1082df8bae1dSRodney W. Grimes /* 1083df8bae1dSRodney W. Grimes * Note that the ipl does not have to be raised at this point. 1084df8bae1dSRodney W. Grimes * The only problem that could arise here is that if two different 1085df8bae1dSRodney W. Grimes * interfaces shared any data. This is not the case. 1086df8bae1dSRodney W. Grimes */ 1087df8bae1dSRodney W. Grimes bp = (struct bpf_if *)arg; 1088df8bae1dSRodney W. Grimes for (d = bp->bif_dlist; d != 0; d = d->bd_next) { 1089df8bae1dSRodney W. Grimes ++d->bd_rcount; 1090df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen); 1091df8bae1dSRodney W. Grimes if (slen != 0) 1092df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, slen, bcopy); 1093df8bae1dSRodney W. Grimes } 1094df8bae1dSRodney W. Grimes } 1095df8bae1dSRodney W. Grimes 1096df8bae1dSRodney W. Grimes /* 1097df8bae1dSRodney W. Grimes * Copy data from an mbuf chain into a buffer. This code is derived 1098df8bae1dSRodney W. Grimes * from m_copydata in sys/uipc_mbuf.c. 1099df8bae1dSRodney W. Grimes */ 1100df8bae1dSRodney W. Grimes static void 1101df8bae1dSRodney W. Grimes bpf_mcopy(src_arg, dst_arg, len) 1102df8bae1dSRodney W. Grimes const void *src_arg; 1103df8bae1dSRodney W. Grimes void *dst_arg; 1104df8bae1dSRodney W. Grimes register u_int len; 1105df8bae1dSRodney W. Grimes { 1106df8bae1dSRodney W. Grimes register const struct mbuf *m; 1107df8bae1dSRodney W. Grimes register u_int count; 1108df8bae1dSRodney W. Grimes u_char *dst; 1109df8bae1dSRodney W. Grimes 1110df8bae1dSRodney W. Grimes m = src_arg; 1111df8bae1dSRodney W. Grimes dst = dst_arg; 1112df8bae1dSRodney W. Grimes while (len > 0) { 1113df8bae1dSRodney W. Grimes if (m == 0) 1114df8bae1dSRodney W. Grimes panic("bpf_mcopy"); 1115df8bae1dSRodney W. Grimes count = min(m->m_len, len); 111694a5d9b6SDavid Greenman (void)memcpy((caddr_t)dst, mtod(m, caddr_t), count); 1117df8bae1dSRodney W. Grimes m = m->m_next; 1118df8bae1dSRodney W. Grimes dst += count; 1119df8bae1dSRodney W. Grimes len -= count; 1120df8bae1dSRodney W. Grimes } 1121df8bae1dSRodney W. Grimes } 1122df8bae1dSRodney W. Grimes 1123df8bae1dSRodney W. Grimes /* 1124df8bae1dSRodney W. Grimes * Incoming linkage from device drivers, when packet is in an mbuf chain. 1125df8bae1dSRodney W. Grimes */ 1126df8bae1dSRodney W. Grimes void 1127df8bae1dSRodney W. Grimes bpf_mtap(arg, m) 1128df8bae1dSRodney W. Grimes caddr_t arg; 1129df8bae1dSRodney W. Grimes struct mbuf *m; 1130df8bae1dSRodney W. Grimes { 1131df8bae1dSRodney W. Grimes struct bpf_if *bp = (struct bpf_if *)arg; 1132df8bae1dSRodney W. Grimes struct bpf_d *d; 1133df8bae1dSRodney W. Grimes u_int pktlen, slen; 1134df8bae1dSRodney W. Grimes struct mbuf *m0; 1135df8bae1dSRodney W. Grimes 1136df8bae1dSRodney W. Grimes pktlen = 0; 1137df8bae1dSRodney W. Grimes for (m0 = m; m0 != 0; m0 = m0->m_next) 1138df8bae1dSRodney W. Grimes pktlen += m0->m_len; 1139df8bae1dSRodney W. Grimes 1140df8bae1dSRodney W. Grimes for (d = bp->bif_dlist; d != 0; d = d->bd_next) { 1141df8bae1dSRodney W. Grimes ++d->bd_rcount; 1142df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0); 1143df8bae1dSRodney W. Grimes if (slen != 0) 1144df8bae1dSRodney W. Grimes catchpacket(d, (u_char *)m, pktlen, slen, bpf_mcopy); 1145df8bae1dSRodney W. Grimes } 1146df8bae1dSRodney W. Grimes } 1147df8bae1dSRodney W. Grimes 1148df8bae1dSRodney W. Grimes /* 1149df8bae1dSRodney W. Grimes * Move the packet data from interface memory (pkt) into the 1150df8bae1dSRodney W. Grimes * store buffer. Return 1 if it's time to wakeup a listener (buffer full), 1151df8bae1dSRodney W. Grimes * otherwise 0. "copy" is the routine called to do the actual data 1152df8bae1dSRodney W. Grimes * transfer. bcopy is passed in to copy contiguous chunks, while 1153df8bae1dSRodney W. Grimes * bpf_mcopy is passed in to copy mbuf chains. In the latter case, 1154df8bae1dSRodney W. Grimes * pkt is really an mbuf. 1155df8bae1dSRodney W. Grimes */ 1156df8bae1dSRodney W. Grimes static void 1157df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, snaplen, cpfn) 1158df8bae1dSRodney W. Grimes register struct bpf_d *d; 1159df8bae1dSRodney W. Grimes register u_char *pkt; 1160df8bae1dSRodney W. Grimes register u_int pktlen, snaplen; 1161df8bae1dSRodney W. Grimes register void (*cpfn)(const void *, void *, u_int); 1162df8bae1dSRodney W. Grimes { 1163df8bae1dSRodney W. Grimes register struct bpf_hdr *hp; 1164df8bae1dSRodney W. Grimes register int totlen, curlen; 1165df8bae1dSRodney W. Grimes register int hdrlen = d->bd_bif->bif_hdrlen; 1166df8bae1dSRodney W. Grimes /* 1167df8bae1dSRodney W. Grimes * Figure out how many bytes to move. If the packet is 1168df8bae1dSRodney W. Grimes * greater or equal to the snapshot length, transfer that 1169df8bae1dSRodney W. Grimes * much. Otherwise, transfer the whole packet (unless 1170df8bae1dSRodney W. Grimes * we hit the buffer size limit). 1171df8bae1dSRodney W. Grimes */ 1172df8bae1dSRodney W. Grimes totlen = hdrlen + min(snaplen, pktlen); 1173df8bae1dSRodney W. Grimes if (totlen > d->bd_bufsize) 1174df8bae1dSRodney W. Grimes totlen = d->bd_bufsize; 1175df8bae1dSRodney W. Grimes 1176df8bae1dSRodney W. Grimes /* 1177df8bae1dSRodney W. Grimes * Round up the end of the previous packet to the next longword. 1178df8bae1dSRodney W. Grimes */ 1179df8bae1dSRodney W. Grimes curlen = BPF_WORDALIGN(d->bd_slen); 1180df8bae1dSRodney W. Grimes if (curlen + totlen > d->bd_bufsize) { 1181df8bae1dSRodney W. Grimes /* 1182df8bae1dSRodney W. Grimes * This packet will overflow the storage buffer. 1183df8bae1dSRodney W. Grimes * Rotate the buffers if we can, then wakeup any 1184df8bae1dSRodney W. Grimes * pending reads. 1185df8bae1dSRodney W. Grimes */ 1186df8bae1dSRodney W. Grimes if (d->bd_fbuf == 0) { 1187df8bae1dSRodney W. Grimes /* 1188df8bae1dSRodney W. Grimes * We haven't completed the previous read yet, 1189df8bae1dSRodney W. Grimes * so drop the packet. 1190df8bae1dSRodney W. Grimes */ 1191df8bae1dSRodney W. Grimes ++d->bd_dcount; 1192df8bae1dSRodney W. Grimes return; 1193df8bae1dSRodney W. Grimes } 1194df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 1195df8bae1dSRodney W. Grimes bpf_wakeup(d); 1196df8bae1dSRodney W. Grimes curlen = 0; 1197df8bae1dSRodney W. Grimes } 1198df8bae1dSRodney W. Grimes else if (d->bd_immediate) 1199df8bae1dSRodney W. Grimes /* 1200df8bae1dSRodney W. Grimes * Immediate mode is set. A packet arrived so any 1201df8bae1dSRodney W. Grimes * reads should be woken up. 1202df8bae1dSRodney W. Grimes */ 1203df8bae1dSRodney W. Grimes bpf_wakeup(d); 1204df8bae1dSRodney W. Grimes 1205df8bae1dSRodney W. Grimes /* 1206df8bae1dSRodney W. Grimes * Append the bpf header. 1207df8bae1dSRodney W. Grimes */ 1208df8bae1dSRodney W. Grimes hp = (struct bpf_hdr *)(d->bd_sbuf + curlen); 1209df8bae1dSRodney W. Grimes #if BSD >= 199103 1210df8bae1dSRodney W. Grimes microtime(&hp->bh_tstamp); 1211df8bae1dSRodney W. Grimes #elif defined(sun) 1212df8bae1dSRodney W. Grimes uniqtime(&hp->bh_tstamp); 1213df8bae1dSRodney W. Grimes #else 1214df8bae1dSRodney W. Grimes hp->bh_tstamp = time; 1215df8bae1dSRodney W. Grimes #endif 1216df8bae1dSRodney W. Grimes hp->bh_datalen = pktlen; 1217df8bae1dSRodney W. Grimes hp->bh_hdrlen = hdrlen; 1218df8bae1dSRodney W. Grimes /* 1219df8bae1dSRodney W. Grimes * Copy the packet data into the store buffer and update its length. 1220df8bae1dSRodney W. Grimes */ 1221df8bae1dSRodney W. Grimes (*cpfn)(pkt, (u_char *)hp + hdrlen, (hp->bh_caplen = totlen - hdrlen)); 1222df8bae1dSRodney W. Grimes d->bd_slen = curlen + totlen; 1223df8bae1dSRodney W. Grimes } 1224df8bae1dSRodney W. Grimes 1225df8bae1dSRodney W. Grimes /* 1226df8bae1dSRodney W. Grimes * Initialize all nonzero fields of a descriptor. 1227df8bae1dSRodney W. Grimes */ 1228df8bae1dSRodney W. Grimes static int 1229df8bae1dSRodney W. Grimes bpf_allocbufs(d) 1230df8bae1dSRodney W. Grimes register struct bpf_d *d; 1231df8bae1dSRodney W. Grimes { 1232df8bae1dSRodney W. Grimes d->bd_fbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); 1233df8bae1dSRodney W. Grimes if (d->bd_fbuf == 0) 1234df8bae1dSRodney W. Grimes return (ENOBUFS); 1235df8bae1dSRodney W. Grimes 1236df8bae1dSRodney W. Grimes d->bd_sbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); 1237df8bae1dSRodney W. Grimes if (d->bd_sbuf == 0) { 1238df8bae1dSRodney W. Grimes free(d->bd_fbuf, M_DEVBUF); 1239df8bae1dSRodney W. Grimes return (ENOBUFS); 1240df8bae1dSRodney W. Grimes } 1241df8bae1dSRodney W. Grimes d->bd_slen = 0; 1242df8bae1dSRodney W. Grimes d->bd_hlen = 0; 1243df8bae1dSRodney W. Grimes return (0); 1244df8bae1dSRodney W. Grimes } 1245df8bae1dSRodney W. Grimes 1246df8bae1dSRodney W. Grimes /* 1247df8bae1dSRodney W. Grimes * Free buffers currently in use by a descriptor. 1248df8bae1dSRodney W. Grimes * Called on close. 1249df8bae1dSRodney W. Grimes */ 1250df8bae1dSRodney W. Grimes static void 1251df8bae1dSRodney W. Grimes bpf_freed(d) 1252df8bae1dSRodney W. Grimes register struct bpf_d *d; 1253df8bae1dSRodney W. Grimes { 1254df8bae1dSRodney W. Grimes /* 1255df8bae1dSRodney W. Grimes * We don't need to lock out interrupts since this descriptor has 1256df8bae1dSRodney W. Grimes * been detached from its interface and it yet hasn't been marked 1257df8bae1dSRodney W. Grimes * free. 1258df8bae1dSRodney W. Grimes */ 1259df8bae1dSRodney W. Grimes if (d->bd_sbuf != 0) { 1260df8bae1dSRodney W. Grimes free(d->bd_sbuf, M_DEVBUF); 1261df8bae1dSRodney W. Grimes if (d->bd_hbuf != 0) 1262df8bae1dSRodney W. Grimes free(d->bd_hbuf, M_DEVBUF); 1263df8bae1dSRodney W. Grimes if (d->bd_fbuf != 0) 1264df8bae1dSRodney W. Grimes free(d->bd_fbuf, M_DEVBUF); 1265df8bae1dSRodney W. Grimes } 1266df8bae1dSRodney W. Grimes if (d->bd_filter) 1267df8bae1dSRodney W. Grimes free((caddr_t)d->bd_filter, M_DEVBUF); 1268df8bae1dSRodney W. Grimes 1269df8bae1dSRodney W. Grimes D_MARKFREE(d); 1270df8bae1dSRodney W. Grimes } 1271df8bae1dSRodney W. Grimes 1272df8bae1dSRodney W. Grimes /* 1273df8bae1dSRodney W. Grimes * Attach an interface to bpf. driverp is a pointer to a (struct bpf_if *) 1274df8bae1dSRodney W. Grimes * in the driver's softc; dlt is the link layer type; hdrlen is the fixed 1275df8bae1dSRodney W. Grimes * size of the link header (variable length headers not yet supported). 1276df8bae1dSRodney W. Grimes */ 1277df8bae1dSRodney W. Grimes void 1278df8bae1dSRodney W. Grimes bpfattach(driverp, ifp, dlt, hdrlen) 1279df8bae1dSRodney W. Grimes caddr_t *driverp; 1280df8bae1dSRodney W. Grimes struct ifnet *ifp; 1281df8bae1dSRodney W. Grimes u_int dlt, hdrlen; 1282df8bae1dSRodney W. Grimes { 1283df8bae1dSRodney W. Grimes struct bpf_if *bp; 1284df8bae1dSRodney W. Grimes int i; 1285df8bae1dSRodney W. Grimes #if BSD < 199103 1286df8bae1dSRodney W. Grimes static struct bpf_if bpf_ifs[NBPFILTER]; 1287df8bae1dSRodney W. Grimes static int bpfifno; 1288df8bae1dSRodney W. Grimes 1289df8bae1dSRodney W. Grimes bp = (bpfifno < NBPFILTER) ? &bpf_ifs[bpfifno++] : 0; 1290df8bae1dSRodney W. Grimes #else 1291df8bae1dSRodney W. Grimes bp = (struct bpf_if *)malloc(sizeof(*bp), M_DEVBUF, M_DONTWAIT); 1292df8bae1dSRodney W. Grimes #endif 1293df8bae1dSRodney W. Grimes if (bp == 0) 1294df8bae1dSRodney W. Grimes panic("bpfattach"); 1295df8bae1dSRodney W. Grimes 1296df8bae1dSRodney W. Grimes bp->bif_dlist = 0; 1297df8bae1dSRodney W. Grimes bp->bif_driverp = (struct bpf_if **)driverp; 1298df8bae1dSRodney W. Grimes bp->bif_ifp = ifp; 1299df8bae1dSRodney W. Grimes bp->bif_dlt = dlt; 1300df8bae1dSRodney W. Grimes 1301df8bae1dSRodney W. Grimes bp->bif_next = bpf_iflist; 1302df8bae1dSRodney W. Grimes bpf_iflist = bp; 1303df8bae1dSRodney W. Grimes 1304df8bae1dSRodney W. Grimes *bp->bif_driverp = 0; 1305df8bae1dSRodney W. Grimes 1306df8bae1dSRodney W. Grimes /* 1307df8bae1dSRodney W. Grimes * Compute the length of the bpf header. This is not necessarily 1308df8bae1dSRodney W. Grimes * equal to SIZEOF_BPF_HDR because we want to insert spacing such 1309df8bae1dSRodney W. Grimes * that the network layer header begins on a longword boundary (for 1310df8bae1dSRodney W. Grimes * performance reasons and to alleviate alignment restrictions). 1311df8bae1dSRodney W. Grimes */ 1312df8bae1dSRodney W. Grimes bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen; 1313df8bae1dSRodney W. Grimes 1314df8bae1dSRodney W. Grimes /* 1315df8bae1dSRodney W. Grimes * Mark all the descriptors free if this hasn't been done. 1316df8bae1dSRodney W. Grimes */ 1317df8bae1dSRodney W. Grimes if (!D_ISFREE(&bpf_dtab[0])) 1318df8bae1dSRodney W. Grimes for (i = 0; i < NBPFILTER; ++i) 1319df8bae1dSRodney W. Grimes D_MARKFREE(&bpf_dtab[i]); 1320df8bae1dSRodney W. Grimes 13212eeab939SGarrett Wollman if (bootverbose) 1322df8bae1dSRodney W. Grimes printf("bpf: %s%d attached\n", ifp->if_name, ifp->if_unit); 1323df8bae1dSRodney W. Grimes } 132453ac6efbSJulian Elischer 132553ac6efbSJulian Elischer 132653ac6efbSJulian Elischer #ifdef JREMOD 132753ac6efbSJulian Elischer struct cdevsw bpf_cdevsw = 132853ac6efbSJulian Elischer { bpfopen, bpfclose, bpfread, bpfwrite, /*23*/ 132953ac6efbSJulian Elischer bpfioctl, nostop, nullreset, nodevtotty,/* bpf */ 133053ac6efbSJulian Elischer bpfselect, nommap, NULL }; 133153ac6efbSJulian Elischer 133253ac6efbSJulian Elischer static bpf_devsw_installed = 0; 133353ac6efbSJulian Elischer 133453ac6efbSJulian Elischer static void bpf_drvinit(void *unused) 133553ac6efbSJulian Elischer { 133653ac6efbSJulian Elischer dev_t dev; 133753ac6efbSJulian Elischer 133853ac6efbSJulian Elischer if( ! bpf_devsw_installed ) { 133953ac6efbSJulian Elischer dev = makedev(CDEV_MAJOR,0); 134053ac6efbSJulian Elischer cdevsw_add(&dev,&bpf_cdevsw,NULL); 134153ac6efbSJulian Elischer bpf_devsw_installed = 1; 134253ac6efbSJulian Elischer #ifdef DEVFS 134353ac6efbSJulian Elischer { 134453ac6efbSJulian Elischer int x; 134553ac6efbSJulian Elischer /* default for a simple device with no probe routine (usually delete this) */ 134653ac6efbSJulian Elischer x=devfs_add_devsw( 134753ac6efbSJulian Elischer /* path name devsw minor type uid gid perm*/ 134853ac6efbSJulian Elischer "/", "bpf", major(dev), 0, DV_CHR, 0, 0, 0600); 134953ac6efbSJulian Elischer } 135053ac6efbSJulian Elischer #endif 135153ac6efbSJulian Elischer } 13527198bf47SJulian Elischer } 135353ac6efbSJulian Elischer 135453ac6efbSJulian Elischer SYSINIT(bpfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,bpf_drvinit,NULL) 135553ac6efbSJulian Elischer 135653ac6efbSJulian Elischer #endif /* JREMOD */ 135753ac6efbSJulian Elischer 1358df8bae1dSRodney W. Grimes #endif 1359