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 * 40d41f24e7SDavid Greenman * $Id: bpf.c,v 1.4 1994/10/09 07:35:03 davidg 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> 55df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 56df8bae1dSRodney W. Grimes #include <sys/buf.h> 57df8bae1dSRodney W. Grimes #include <sys/time.h> 58df8bae1dSRodney W. Grimes #include <sys/proc.h> 59df8bae1dSRodney W. Grimes #include <sys/user.h> 60df8bae1dSRodney W. Grimes #include <sys/ioctl.h> 61df8bae1dSRodney W. Grimes 62df8bae1dSRodney W. Grimes #include <sys/file.h> 63df8bae1dSRodney W. Grimes #if defined(sparc) && BSD < 199103 64df8bae1dSRodney W. Grimes #include <sys/stream.h> 65df8bae1dSRodney W. Grimes #endif 66df8bae1dSRodney W. Grimes #include <sys/tty.h> 67df8bae1dSRodney W. Grimes #include <sys/uio.h> 68df8bae1dSRodney W. Grimes 69df8bae1dSRodney W. Grimes #include <sys/protosw.h> 70df8bae1dSRodney W. Grimes #include <sys/socket.h> 71df8bae1dSRodney W. Grimes #include <net/if.h> 72df8bae1dSRodney W. Grimes 73df8bae1dSRodney W. Grimes #include <net/bpf.h> 74df8bae1dSRodney W. Grimes #include <net/bpfdesc.h> 75df8bae1dSRodney W. Grimes 76df8bae1dSRodney W. Grimes #include <sys/errno.h> 77df8bae1dSRodney W. Grimes 78df8bae1dSRodney W. Grimes #include <netinet/in.h> 79df8bae1dSRodney W. Grimes #include <netinet/if_ether.h> 80df8bae1dSRodney W. Grimes #include <sys/kernel.h> 81df8bae1dSRodney W. Grimes 82df8bae1dSRodney W. Grimes /* 83df8bae1dSRodney W. Grimes * Older BSDs don't have kernel malloc. 84df8bae1dSRodney W. Grimes */ 85df8bae1dSRodney W. Grimes #if BSD < 199103 86df8bae1dSRodney W. Grimes extern bcopy(); 87df8bae1dSRodney W. Grimes static caddr_t bpf_alloc(); 88df8bae1dSRodney W. Grimes #include <net/bpf_compat.h> 89df8bae1dSRodney W. Grimes #define BPF_BUFSIZE (MCLBYTES-8) 90df8bae1dSRodney W. Grimes #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio) 91df8bae1dSRodney W. Grimes #else 92df8bae1dSRodney W. Grimes #define BPF_BUFSIZE 4096 93df8bae1dSRodney W. Grimes #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio) 94df8bae1dSRodney W. Grimes #endif 95df8bae1dSRodney W. Grimes 96df8bae1dSRodney W. Grimes #define PRINET 26 /* interruptible */ 97df8bae1dSRodney W. Grimes 98df8bae1dSRodney W. Grimes /* 99df8bae1dSRodney W. Grimes * The default read buffer size is patchable. 100df8bae1dSRodney W. Grimes */ 101df8bae1dSRodney W. Grimes int bpf_bufsize = BPF_BUFSIZE; 102df8bae1dSRodney W. Grimes 103df8bae1dSRodney W. Grimes /* 104df8bae1dSRodney W. Grimes * bpf_iflist is the list of interfaces; each corresponds to an ifnet 105df8bae1dSRodney W. Grimes * bpf_dtab holds the descriptors, indexed by minor device # 106df8bae1dSRodney W. Grimes */ 107df8bae1dSRodney W. Grimes struct bpf_if *bpf_iflist; 108df8bae1dSRodney W. Grimes struct bpf_d bpf_dtab[NBPFILTER]; 109df8bae1dSRodney W. Grimes 110df8bae1dSRodney W. Grimes #if BSD >= 199207 111df8bae1dSRodney W. Grimes /* 112df8bae1dSRodney W. Grimes * bpfilterattach() is called at boot time in new systems. We do 113df8bae1dSRodney W. Grimes * nothing here since old systems will not call this. 114df8bae1dSRodney W. Grimes */ 115df8bae1dSRodney W. Grimes /* ARGSUSED */ 116df8bae1dSRodney W. Grimes void 117df8bae1dSRodney W. Grimes bpfilterattach(n) 118df8bae1dSRodney W. Grimes int n; 119df8bae1dSRodney W. Grimes { 120df8bae1dSRodney W. Grimes } 121df8bae1dSRodney W. Grimes #endif 122df8bae1dSRodney W. Grimes 123df8bae1dSRodney W. Grimes static int bpf_allocbufs __P((struct bpf_d *)); 124df8bae1dSRodney W. Grimes static void bpf_freed __P((struct bpf_d *)); 125df8bae1dSRodney W. Grimes static void bpf_ifname __P((struct ifnet *, struct ifreq *)); 126df8bae1dSRodney W. Grimes static void bpf_mcopy __P((const void *, void *, u_int)); 127df8bae1dSRodney W. Grimes static int bpf_movein __P((struct uio *, int, 128df8bae1dSRodney W. Grimes struct mbuf **, struct sockaddr *, int *)); 129df8bae1dSRodney W. Grimes static int bpf_setif __P((struct bpf_d *, struct ifreq *)); 130df8bae1dSRodney W. Grimes static inline void 131df8bae1dSRodney W. Grimes bpf_wakeup __P((struct bpf_d *)); 132df8bae1dSRodney W. Grimes static void catchpacket __P((struct bpf_d *, u_char *, u_int, 133df8bae1dSRodney W. Grimes u_int, void (*)(const void *, void *, u_int))); 134df8bae1dSRodney W. Grimes static void reset_d __P((struct bpf_d *)); 135df8bae1dSRodney W. Grimes 136df8bae1dSRodney W. Grimes static int 137df8bae1dSRodney W. Grimes bpf_movein(uio, linktype, mp, sockp, datlen) 138df8bae1dSRodney W. Grimes register struct uio *uio; 139df8bae1dSRodney W. Grimes int linktype, *datlen; 140df8bae1dSRodney W. Grimes register struct mbuf **mp; 141df8bae1dSRodney W. Grimes register struct sockaddr *sockp; 142df8bae1dSRodney W. Grimes { 143df8bae1dSRodney W. Grimes struct mbuf *m; 144df8bae1dSRodney W. Grimes int error; 145df8bae1dSRodney W. Grimes int len; 146df8bae1dSRodney W. Grimes int hlen; 147df8bae1dSRodney W. Grimes 148df8bae1dSRodney W. Grimes /* 149df8bae1dSRodney W. Grimes * Build a sockaddr based on the data link layer type. 150df8bae1dSRodney W. Grimes * We do this at this level because the ethernet header 151df8bae1dSRodney W. Grimes * is copied directly into the data field of the sockaddr. 152df8bae1dSRodney W. Grimes * In the case of SLIP, there is no header and the packet 153df8bae1dSRodney W. Grimes * is forwarded as is. 154df8bae1dSRodney W. Grimes * Also, we are careful to leave room at the front of the mbuf 155df8bae1dSRodney W. Grimes * for the link level header. 156df8bae1dSRodney W. Grimes */ 157df8bae1dSRodney W. Grimes switch (linktype) { 158df8bae1dSRodney W. Grimes 159df8bae1dSRodney W. Grimes case DLT_SLIP: 160df8bae1dSRodney W. Grimes sockp->sa_family = AF_INET; 161df8bae1dSRodney W. Grimes hlen = 0; 162df8bae1dSRodney W. Grimes break; 163df8bae1dSRodney W. Grimes 164df8bae1dSRodney W. Grimes case DLT_EN10MB: 165df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 166df8bae1dSRodney W. Grimes /* XXX Would MAXLINKHDR be better? */ 167df8bae1dSRodney W. Grimes hlen = sizeof(struct ether_header); 168df8bae1dSRodney W. Grimes break; 169df8bae1dSRodney W. Grimes 170df8bae1dSRodney W. Grimes case DLT_FDDI: 171d41f24e7SDavid Greenman #if defined(__FreeBSD__) || defined(__bsdi__) 172d41f24e7SDavid Greenman sockp->sa_family = AF_IMPLINK; 173d41f24e7SDavid Greenman hlen = 0; 174d41f24e7SDavid Greenman #else 175df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 176df8bae1dSRodney W. Grimes /* XXX 4(FORMAC)+6(dst)+6(src)+3(LLC)+5(SNAP) */ 177df8bae1dSRodney W. Grimes hlen = 24; 178d41f24e7SDavid Greenman #endif 179df8bae1dSRodney W. Grimes break; 180df8bae1dSRodney W. Grimes 181df8bae1dSRodney W. Grimes case DLT_NULL: 182df8bae1dSRodney W. Grimes sockp->sa_family = AF_UNSPEC; 183df8bae1dSRodney W. Grimes hlen = 0; 184df8bae1dSRodney W. Grimes break; 185df8bae1dSRodney W. Grimes 186df8bae1dSRodney W. Grimes default: 187df8bae1dSRodney W. Grimes return (EIO); 188df8bae1dSRodney W. Grimes } 189df8bae1dSRodney W. Grimes 190df8bae1dSRodney W. Grimes len = uio->uio_resid; 191df8bae1dSRodney W. Grimes *datlen = len - hlen; 192df8bae1dSRodney W. Grimes if ((unsigned)len > MCLBYTES) 193df8bae1dSRodney W. Grimes return (EIO); 194df8bae1dSRodney W. Grimes 195df8bae1dSRodney W. Grimes MGET(m, M_WAIT, MT_DATA); 196df8bae1dSRodney W. Grimes if (m == 0) 197df8bae1dSRodney W. Grimes return (ENOBUFS); 198df8bae1dSRodney W. Grimes if (len > MLEN) { 199df8bae1dSRodney W. Grimes #if BSD >= 199103 200df8bae1dSRodney W. Grimes MCLGET(m, M_WAIT); 201df8bae1dSRodney W. Grimes if ((m->m_flags & M_EXT) == 0) { 202df8bae1dSRodney W. Grimes #else 203df8bae1dSRodney W. Grimes MCLGET(m); 204df8bae1dSRodney W. Grimes if (m->m_len != MCLBYTES) { 205df8bae1dSRodney W. Grimes #endif 206df8bae1dSRodney W. Grimes error = ENOBUFS; 207df8bae1dSRodney W. Grimes goto bad; 208df8bae1dSRodney W. Grimes } 209df8bae1dSRodney W. Grimes } 210df8bae1dSRodney W. Grimes m->m_len = len; 211df8bae1dSRodney W. Grimes *mp = m; 212df8bae1dSRodney W. Grimes /* 213df8bae1dSRodney W. Grimes * Make room for link header. 214df8bae1dSRodney W. Grimes */ 215df8bae1dSRodney W. Grimes if (hlen != 0) { 216df8bae1dSRodney W. Grimes m->m_len -= hlen; 217df8bae1dSRodney W. Grimes #if BSD >= 199103 218df8bae1dSRodney W. Grimes m->m_data += hlen; /* XXX */ 219df8bae1dSRodney W. Grimes #else 220df8bae1dSRodney W. Grimes m->m_off += hlen; 221df8bae1dSRodney W. Grimes #endif 222df8bae1dSRodney W. Grimes error = UIOMOVE((caddr_t)sockp->sa_data, hlen, UIO_WRITE, uio); 223df8bae1dSRodney W. Grimes if (error) 224df8bae1dSRodney W. Grimes goto bad; 225df8bae1dSRodney W. Grimes } 226df8bae1dSRodney W. Grimes error = UIOMOVE(mtod(m, caddr_t), len - hlen, UIO_WRITE, uio); 227df8bae1dSRodney W. Grimes if (!error) 228df8bae1dSRodney W. Grimes return (0); 229df8bae1dSRodney W. Grimes bad: 230df8bae1dSRodney W. Grimes m_freem(m); 231df8bae1dSRodney W. Grimes return (error); 232df8bae1dSRodney W. Grimes } 233df8bae1dSRodney W. Grimes 234df8bae1dSRodney W. Grimes /* 235df8bae1dSRodney W. Grimes * Attach file to the bpf interface, i.e. make d listen on bp. 236df8bae1dSRodney W. Grimes * Must be called at splimp. 237df8bae1dSRodney W. Grimes */ 238df8bae1dSRodney W. Grimes static void 239df8bae1dSRodney W. Grimes bpf_attachd(d, bp) 240df8bae1dSRodney W. Grimes struct bpf_d *d; 241df8bae1dSRodney W. Grimes struct bpf_if *bp; 242df8bae1dSRodney W. Grimes { 243df8bae1dSRodney W. Grimes /* 244df8bae1dSRodney W. Grimes * Point d at bp, and add d to the interface's list of listeners. 245df8bae1dSRodney W. Grimes * Finally, point the driver's bpf cookie at the interface so 246df8bae1dSRodney W. Grimes * it will divert packets to bpf. 247df8bae1dSRodney W. Grimes */ 248df8bae1dSRodney W. Grimes d->bd_bif = bp; 249df8bae1dSRodney W. Grimes d->bd_next = bp->bif_dlist; 250df8bae1dSRodney W. Grimes bp->bif_dlist = d; 251df8bae1dSRodney W. Grimes 252df8bae1dSRodney W. Grimes *bp->bif_driverp = bp; 253df8bae1dSRodney W. Grimes } 254df8bae1dSRodney W. Grimes 255df8bae1dSRodney W. Grimes /* 256df8bae1dSRodney W. Grimes * Detach a file from its interface. 257df8bae1dSRodney W. Grimes */ 258df8bae1dSRodney W. Grimes static void 259df8bae1dSRodney W. Grimes bpf_detachd(d) 260df8bae1dSRodney W. Grimes struct bpf_d *d; 261df8bae1dSRodney W. Grimes { 262df8bae1dSRodney W. Grimes struct bpf_d **p; 263df8bae1dSRodney W. Grimes struct bpf_if *bp; 264df8bae1dSRodney W. Grimes 265df8bae1dSRodney W. Grimes bp = d->bd_bif; 266df8bae1dSRodney W. Grimes /* 267df8bae1dSRodney W. Grimes * Check if this descriptor had requested promiscuous mode. 268df8bae1dSRodney W. Grimes * If so, turn it off. 269df8bae1dSRodney W. Grimes */ 270df8bae1dSRodney W. Grimes if (d->bd_promisc) { 271df8bae1dSRodney W. Grimes d->bd_promisc = 0; 272df8bae1dSRodney W. Grimes if (ifpromisc(bp->bif_ifp, 0)) 273df8bae1dSRodney W. Grimes /* 274df8bae1dSRodney W. Grimes * Something is really wrong if we were able to put 275df8bae1dSRodney W. Grimes * the driver into promiscuous mode, but can't 276df8bae1dSRodney W. Grimes * take it out. 277df8bae1dSRodney W. Grimes */ 278df8bae1dSRodney W. Grimes panic("bpf: ifpromisc failed"); 279df8bae1dSRodney W. Grimes } 280df8bae1dSRodney W. Grimes /* Remove d from the interface's descriptor list. */ 281df8bae1dSRodney W. Grimes p = &bp->bif_dlist; 282df8bae1dSRodney W. Grimes while (*p != d) { 283df8bae1dSRodney W. Grimes p = &(*p)->bd_next; 284df8bae1dSRodney W. Grimes if (*p == 0) 285df8bae1dSRodney W. Grimes panic("bpf_detachd: descriptor not in list"); 286df8bae1dSRodney W. Grimes } 287df8bae1dSRodney W. Grimes *p = (*p)->bd_next; 288df8bae1dSRodney W. Grimes if (bp->bif_dlist == 0) 289df8bae1dSRodney W. Grimes /* 290df8bae1dSRodney W. Grimes * Let the driver know that there are no more listeners. 291df8bae1dSRodney W. Grimes */ 292df8bae1dSRodney W. Grimes *d->bd_bif->bif_driverp = 0; 293df8bae1dSRodney W. Grimes d->bd_bif = 0; 294df8bae1dSRodney W. Grimes } 295df8bae1dSRodney W. Grimes 296df8bae1dSRodney W. Grimes 297df8bae1dSRodney W. Grimes /* 298df8bae1dSRodney W. Grimes * Mark a descriptor free by making it point to itself. 299df8bae1dSRodney W. Grimes * This is probably cheaper than marking with a constant since 300df8bae1dSRodney W. Grimes * the address should be in a register anyway. 301df8bae1dSRodney W. Grimes */ 302df8bae1dSRodney W. Grimes #define D_ISFREE(d) ((d) == (d)->bd_next) 303df8bae1dSRodney W. Grimes #define D_MARKFREE(d) ((d)->bd_next = (d)) 304df8bae1dSRodney W. Grimes #define D_MARKUSED(d) ((d)->bd_next = 0) 305df8bae1dSRodney W. Grimes 306df8bae1dSRodney W. Grimes /* 307df8bae1dSRodney W. Grimes * Open ethernet device. Returns ENXIO for illegal minor device number, 308df8bae1dSRodney W. Grimes * EBUSY if file is open by another process. 309df8bae1dSRodney W. Grimes */ 310df8bae1dSRodney W. Grimes /* ARGSUSED */ 311df8bae1dSRodney W. Grimes int 312df8bae1dSRodney W. Grimes bpfopen(dev, flag) 313df8bae1dSRodney W. Grimes dev_t dev; 314df8bae1dSRodney W. Grimes int flag; 315df8bae1dSRodney W. Grimes { 316df8bae1dSRodney W. Grimes register struct bpf_d *d; 317df8bae1dSRodney W. Grimes 318df8bae1dSRodney W. Grimes if (minor(dev) >= NBPFILTER) 319df8bae1dSRodney W. Grimes return (ENXIO); 320df8bae1dSRodney W. Grimes /* 321df8bae1dSRodney W. Grimes * Each minor can be opened by only one process. If the requested 322df8bae1dSRodney W. Grimes * minor is in use, return EBUSY. 323df8bae1dSRodney W. Grimes */ 324df8bae1dSRodney W. Grimes d = &bpf_dtab[minor(dev)]; 325df8bae1dSRodney W. Grimes if (!D_ISFREE(d)) 326df8bae1dSRodney W. Grimes return (EBUSY); 327df8bae1dSRodney W. Grimes 328df8bae1dSRodney W. Grimes /* Mark "free" and do most initialization. */ 329df8bae1dSRodney W. Grimes bzero((char *)d, sizeof(*d)); 330df8bae1dSRodney W. Grimes d->bd_bufsize = bpf_bufsize; 331df8bae1dSRodney W. Grimes 332df8bae1dSRodney W. Grimes return (0); 333df8bae1dSRodney W. Grimes } 334df8bae1dSRodney W. Grimes 335df8bae1dSRodney W. Grimes /* 336df8bae1dSRodney W. Grimes * Close the descriptor by detaching it from its interface, 337df8bae1dSRodney W. Grimes * deallocating its buffers, and marking it free. 338df8bae1dSRodney W. Grimes */ 339df8bae1dSRodney W. Grimes /* ARGSUSED */ 340df8bae1dSRodney W. Grimes int 341df8bae1dSRodney W. Grimes bpfclose(dev, flag) 342df8bae1dSRodney W. Grimes dev_t dev; 343df8bae1dSRodney W. Grimes int flag; 344df8bae1dSRodney W. Grimes { 345df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 346df8bae1dSRodney W. Grimes register int s; 347df8bae1dSRodney W. Grimes 348df8bae1dSRodney W. Grimes s = splimp(); 349df8bae1dSRodney W. Grimes if (d->bd_bif) 350df8bae1dSRodney W. Grimes bpf_detachd(d); 351df8bae1dSRodney W. Grimes splx(s); 352df8bae1dSRodney W. Grimes bpf_freed(d); 353df8bae1dSRodney W. Grimes 354df8bae1dSRodney W. Grimes return (0); 355df8bae1dSRodney W. Grimes } 356df8bae1dSRodney W. Grimes 357df8bae1dSRodney W. Grimes /* 358df8bae1dSRodney W. Grimes * Support for SunOS, which does not have tsleep. 359df8bae1dSRodney W. Grimes */ 360df8bae1dSRodney W. Grimes #if BSD < 199103 361df8bae1dSRodney W. Grimes static 362df8bae1dSRodney W. Grimes bpf_timeout(arg) 363df8bae1dSRodney W. Grimes caddr_t arg; 364df8bae1dSRodney W. Grimes { 365df8bae1dSRodney W. Grimes struct bpf_d *d = (struct bpf_d *)arg; 366df8bae1dSRodney W. Grimes d->bd_timedout = 1; 367df8bae1dSRodney W. Grimes wakeup(arg); 368df8bae1dSRodney W. Grimes } 369df8bae1dSRodney W. Grimes 370df8bae1dSRodney W. Grimes #define BPF_SLEEP(chan, pri, s, t) bpf_sleep((struct bpf_d *)chan) 371df8bae1dSRodney W. Grimes 372df8bae1dSRodney W. Grimes int 373df8bae1dSRodney W. Grimes bpf_sleep(d) 374df8bae1dSRodney W. Grimes register struct bpf_d *d; 375df8bae1dSRodney W. Grimes { 376df8bae1dSRodney W. Grimes register int rto = d->bd_rtout; 377df8bae1dSRodney W. Grimes register int st; 378df8bae1dSRodney W. Grimes 379df8bae1dSRodney W. Grimes if (rto != 0) { 380df8bae1dSRodney W. Grimes d->bd_timedout = 0; 381df8bae1dSRodney W. Grimes timeout(bpf_timeout, (caddr_t)d, rto); 382df8bae1dSRodney W. Grimes } 383df8bae1dSRodney W. Grimes st = sleep((caddr_t)d, PRINET|PCATCH); 384df8bae1dSRodney W. Grimes if (rto != 0) { 385df8bae1dSRodney W. Grimes if (d->bd_timedout == 0) 386df8bae1dSRodney W. Grimes untimeout(bpf_timeout, (caddr_t)d); 387df8bae1dSRodney W. Grimes else if (st == 0) 388df8bae1dSRodney W. Grimes return EWOULDBLOCK; 389df8bae1dSRodney W. Grimes } 390df8bae1dSRodney W. Grimes return (st != 0) ? EINTR : 0; 391df8bae1dSRodney W. Grimes } 392df8bae1dSRodney W. Grimes #else 393df8bae1dSRodney W. Grimes #define BPF_SLEEP tsleep 394df8bae1dSRodney W. Grimes #endif 395df8bae1dSRodney W. Grimes 396df8bae1dSRodney W. Grimes /* 397df8bae1dSRodney W. Grimes * Rotate the packet buffers in descriptor d. Move the store buffer 398df8bae1dSRodney W. Grimes * into the hold slot, and the free buffer into the store slot. 399df8bae1dSRodney W. Grimes * Zero the length of the new store buffer. 400df8bae1dSRodney W. Grimes */ 401df8bae1dSRodney W. Grimes #define ROTATE_BUFFERS(d) \ 402df8bae1dSRodney W. Grimes (d)->bd_hbuf = (d)->bd_sbuf; \ 403df8bae1dSRodney W. Grimes (d)->bd_hlen = (d)->bd_slen; \ 404df8bae1dSRodney W. Grimes (d)->bd_sbuf = (d)->bd_fbuf; \ 405df8bae1dSRodney W. Grimes (d)->bd_slen = 0; \ 406df8bae1dSRodney W. Grimes (d)->bd_fbuf = 0; 407df8bae1dSRodney W. Grimes /* 408df8bae1dSRodney W. Grimes * bpfread - read next chunk of packets from buffers 409df8bae1dSRodney W. Grimes */ 410df8bae1dSRodney W. Grimes int 411df8bae1dSRodney W. Grimes bpfread(dev, uio) 412df8bae1dSRodney W. Grimes dev_t dev; 413df8bae1dSRodney W. Grimes register struct uio *uio; 414df8bae1dSRodney W. Grimes { 415df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 416df8bae1dSRodney W. Grimes int error; 417df8bae1dSRodney W. Grimes int s; 418df8bae1dSRodney W. Grimes 419df8bae1dSRodney W. Grimes /* 420df8bae1dSRodney W. Grimes * Restrict application to use a buffer the same size as 421df8bae1dSRodney W. Grimes * as kernel buffers. 422df8bae1dSRodney W. Grimes */ 423df8bae1dSRodney W. Grimes if (uio->uio_resid != d->bd_bufsize) 424df8bae1dSRodney W. Grimes return (EINVAL); 425df8bae1dSRodney W. Grimes 426df8bae1dSRodney W. Grimes s = splimp(); 427df8bae1dSRodney W. Grimes /* 428df8bae1dSRodney W. Grimes * If the hold buffer is empty, then do a timed sleep, which 429df8bae1dSRodney W. Grimes * ends when the timeout expires or when enough packets 430df8bae1dSRodney W. Grimes * have arrived to fill the store buffer. 431df8bae1dSRodney W. Grimes */ 432df8bae1dSRodney W. Grimes while (d->bd_hbuf == 0) { 433df8bae1dSRodney W. Grimes if (d->bd_immediate && d->bd_slen != 0) { 434df8bae1dSRodney W. Grimes /* 435df8bae1dSRodney W. Grimes * A packet(s) either arrived since the previous 436df8bae1dSRodney W. Grimes * read or arrived while we were asleep. 437df8bae1dSRodney W. Grimes * Rotate the buffers and return what's here. 438df8bae1dSRodney W. Grimes */ 439df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 440df8bae1dSRodney W. Grimes break; 441df8bae1dSRodney W. Grimes } 442df8bae1dSRodney W. Grimes error = BPF_SLEEP((caddr_t)d, PRINET|PCATCH, "bpf", 443df8bae1dSRodney W. Grimes d->bd_rtout); 444df8bae1dSRodney W. Grimes if (error == EINTR || error == ERESTART) { 445df8bae1dSRodney W. Grimes splx(s); 446df8bae1dSRodney W. Grimes return (error); 447df8bae1dSRodney W. Grimes } 448df8bae1dSRodney W. Grimes if (error == EWOULDBLOCK) { 449df8bae1dSRodney W. Grimes /* 450df8bae1dSRodney W. Grimes * On a timeout, return what's in the buffer, 451df8bae1dSRodney W. Grimes * which may be nothing. If there is something 452df8bae1dSRodney W. Grimes * in the store buffer, we can rotate the buffers. 453df8bae1dSRodney W. Grimes */ 454df8bae1dSRodney W. Grimes if (d->bd_hbuf) 455df8bae1dSRodney W. Grimes /* 456df8bae1dSRodney W. Grimes * We filled up the buffer in between 457df8bae1dSRodney W. Grimes * getting the timeout and arriving 458df8bae1dSRodney W. Grimes * here, so we don't need to rotate. 459df8bae1dSRodney W. Grimes */ 460df8bae1dSRodney W. Grimes break; 461df8bae1dSRodney W. Grimes 462df8bae1dSRodney W. Grimes if (d->bd_slen == 0) { 463df8bae1dSRodney W. Grimes splx(s); 464df8bae1dSRodney W. Grimes return (0); 465df8bae1dSRodney W. Grimes } 466df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 467df8bae1dSRodney W. Grimes break; 468df8bae1dSRodney W. Grimes } 469df8bae1dSRodney W. Grimes } 470df8bae1dSRodney W. Grimes /* 471df8bae1dSRodney W. Grimes * At this point, we know we have something in the hold slot. 472df8bae1dSRodney W. Grimes */ 473df8bae1dSRodney W. Grimes splx(s); 474df8bae1dSRodney W. Grimes 475df8bae1dSRodney W. Grimes /* 476df8bae1dSRodney W. Grimes * Move data from hold buffer into user space. 477df8bae1dSRodney W. Grimes * We know the entire buffer is transferred since 478df8bae1dSRodney W. Grimes * we checked above that the read buffer is bpf_bufsize bytes. 479df8bae1dSRodney W. Grimes */ 480df8bae1dSRodney W. Grimes error = UIOMOVE(d->bd_hbuf, d->bd_hlen, UIO_READ, uio); 481df8bae1dSRodney W. Grimes 482df8bae1dSRodney W. Grimes s = splimp(); 483df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 484df8bae1dSRodney W. Grimes d->bd_hbuf = 0; 485df8bae1dSRodney W. Grimes d->bd_hlen = 0; 486df8bae1dSRodney W. Grimes splx(s); 487df8bae1dSRodney W. Grimes 488df8bae1dSRodney W. Grimes return (error); 489df8bae1dSRodney W. Grimes } 490df8bae1dSRodney W. Grimes 491df8bae1dSRodney W. Grimes 492df8bae1dSRodney W. Grimes /* 493df8bae1dSRodney W. Grimes * If there are processes sleeping on this descriptor, wake them up. 494df8bae1dSRodney W. Grimes */ 495df8bae1dSRodney W. Grimes static inline void 496df8bae1dSRodney W. Grimes bpf_wakeup(d) 497df8bae1dSRodney W. Grimes register struct bpf_d *d; 498df8bae1dSRodney W. Grimes { 499df8bae1dSRodney W. Grimes wakeup((caddr_t)d); 500df8bae1dSRodney W. Grimes #if BSD >= 199103 501df8bae1dSRodney W. Grimes selwakeup(&d->bd_sel); 502df8bae1dSRodney W. Grimes /* XXX */ 503df8bae1dSRodney W. Grimes d->bd_sel.si_pid = 0; 504df8bae1dSRodney W. Grimes #else 505df8bae1dSRodney W. Grimes if (d->bd_selproc) { 506df8bae1dSRodney W. Grimes selwakeup(d->bd_selproc, (int)d->bd_selcoll); 507df8bae1dSRodney W. Grimes d->bd_selcoll = 0; 508df8bae1dSRodney W. Grimes d->bd_selproc = 0; 509df8bae1dSRodney W. Grimes } 510df8bae1dSRodney W. Grimes #endif 511df8bae1dSRodney W. Grimes } 512df8bae1dSRodney W. Grimes 513df8bae1dSRodney W. Grimes int 514df8bae1dSRodney W. Grimes bpfwrite(dev, uio) 515df8bae1dSRodney W. Grimes dev_t dev; 516df8bae1dSRodney W. Grimes struct uio *uio; 517df8bae1dSRodney W. Grimes { 518df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 519df8bae1dSRodney W. Grimes struct ifnet *ifp; 520df8bae1dSRodney W. Grimes struct mbuf *m; 521df8bae1dSRodney W. Grimes int error, s; 522df8bae1dSRodney W. Grimes static struct sockaddr dst; 523df8bae1dSRodney W. Grimes int datlen; 524df8bae1dSRodney W. Grimes 525df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 526df8bae1dSRodney W. Grimes return (ENXIO); 527df8bae1dSRodney W. Grimes 528df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 529df8bae1dSRodney W. Grimes 530df8bae1dSRodney W. Grimes if (uio->uio_resid == 0) 531df8bae1dSRodney W. Grimes return (0); 532df8bae1dSRodney W. Grimes 533df8bae1dSRodney W. Grimes error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, &datlen); 534df8bae1dSRodney W. Grimes if (error) 535df8bae1dSRodney W. Grimes return (error); 536df8bae1dSRodney W. Grimes 537df8bae1dSRodney W. Grimes if (datlen > ifp->if_mtu) 538df8bae1dSRodney W. Grimes return (EMSGSIZE); 539df8bae1dSRodney W. Grimes 540df8bae1dSRodney W. Grimes s = splnet(); 541df8bae1dSRodney W. Grimes #if BSD >= 199103 542df8bae1dSRodney W. Grimes error = (*ifp->if_output)(ifp, m, &dst, (struct rtentry *)0); 543df8bae1dSRodney W. Grimes #else 544df8bae1dSRodney W. Grimes error = (*ifp->if_output)(ifp, m, &dst); 545df8bae1dSRodney W. Grimes #endif 546df8bae1dSRodney W. Grimes splx(s); 547df8bae1dSRodney W. Grimes /* 548df8bae1dSRodney W. Grimes * The driver frees the mbuf. 549df8bae1dSRodney W. Grimes */ 550df8bae1dSRodney W. Grimes return (error); 551df8bae1dSRodney W. Grimes } 552df8bae1dSRodney W. Grimes 553df8bae1dSRodney W. Grimes /* 554df8bae1dSRodney W. Grimes * Reset a descriptor by flushing its packet buffer and clearing the 555df8bae1dSRodney W. Grimes * receive and drop counts. Should be called at splimp. 556df8bae1dSRodney W. Grimes */ 557df8bae1dSRodney W. Grimes static void 558df8bae1dSRodney W. Grimes reset_d(d) 559df8bae1dSRodney W. Grimes struct bpf_d *d; 560df8bae1dSRodney W. Grimes { 561df8bae1dSRodney W. Grimes if (d->bd_hbuf) { 562df8bae1dSRodney W. Grimes /* Free the hold buffer. */ 563df8bae1dSRodney W. Grimes d->bd_fbuf = d->bd_hbuf; 564df8bae1dSRodney W. Grimes d->bd_hbuf = 0; 565df8bae1dSRodney W. Grimes } 566df8bae1dSRodney W. Grimes d->bd_slen = 0; 567df8bae1dSRodney W. Grimes d->bd_hlen = 0; 568df8bae1dSRodney W. Grimes d->bd_rcount = 0; 569df8bae1dSRodney W. Grimes d->bd_dcount = 0; 570df8bae1dSRodney W. Grimes } 571df8bae1dSRodney W. Grimes 572df8bae1dSRodney W. Grimes /* 573df8bae1dSRodney W. Grimes * FIONREAD Check for read packet available. 574df8bae1dSRodney W. Grimes * SIOCGIFADDR Get interface address - convenient hook to driver. 575df8bae1dSRodney W. Grimes * BIOCGBLEN Get buffer len [for read()]. 576df8bae1dSRodney W. Grimes * BIOCSETF Set ethernet read filter. 577df8bae1dSRodney W. Grimes * BIOCFLUSH Flush read packet buffer. 578df8bae1dSRodney W. Grimes * BIOCPROMISC Put interface into promiscuous mode. 579df8bae1dSRodney W. Grimes * BIOCGDLT Get link layer type. 580df8bae1dSRodney W. Grimes * BIOCGETIF Get interface name. 581df8bae1dSRodney W. Grimes * BIOCSETIF Set interface. 582df8bae1dSRodney W. Grimes * BIOCSRTIMEOUT Set read timeout. 583df8bae1dSRodney W. Grimes * BIOCGRTIMEOUT Get read timeout. 584df8bae1dSRodney W. Grimes * BIOCGSTATS Get packet stats. 585df8bae1dSRodney W. Grimes * BIOCIMMEDIATE Set immediate mode. 586df8bae1dSRodney W. Grimes * BIOCVERSION Get filter language version. 587df8bae1dSRodney W. Grimes */ 588df8bae1dSRodney W. Grimes /* ARGSUSED */ 589df8bae1dSRodney W. Grimes int 590df8bae1dSRodney W. Grimes bpfioctl(dev, cmd, addr, flag) 591df8bae1dSRodney W. Grimes dev_t dev; 592df8bae1dSRodney W. Grimes int cmd; 593df8bae1dSRodney W. Grimes caddr_t addr; 594df8bae1dSRodney W. Grimes int flag; 595df8bae1dSRodney W. Grimes { 596df8bae1dSRodney W. Grimes register struct bpf_d *d = &bpf_dtab[minor(dev)]; 597df8bae1dSRodney W. Grimes int s, error = 0; 598df8bae1dSRodney W. Grimes 599df8bae1dSRodney W. Grimes switch (cmd) { 600df8bae1dSRodney W. Grimes 601df8bae1dSRodney W. Grimes default: 602df8bae1dSRodney W. Grimes error = EINVAL; 603df8bae1dSRodney W. Grimes break; 604df8bae1dSRodney W. Grimes 605df8bae1dSRodney W. Grimes /* 606df8bae1dSRodney W. Grimes * Check for read packet available. 607df8bae1dSRodney W. Grimes */ 608df8bae1dSRodney W. Grimes case FIONREAD: 609df8bae1dSRodney W. Grimes { 610df8bae1dSRodney W. Grimes int n; 611df8bae1dSRodney W. Grimes 612df8bae1dSRodney W. Grimes s = splimp(); 613df8bae1dSRodney W. Grimes n = d->bd_slen; 614df8bae1dSRodney W. Grimes if (d->bd_hbuf) 615df8bae1dSRodney W. Grimes n += d->bd_hlen; 616df8bae1dSRodney W. Grimes splx(s); 617df8bae1dSRodney W. Grimes 618df8bae1dSRodney W. Grimes *(int *)addr = n; 619df8bae1dSRodney W. Grimes break; 620df8bae1dSRodney W. Grimes } 621df8bae1dSRodney W. Grimes 622df8bae1dSRodney W. Grimes case SIOCGIFADDR: 623df8bae1dSRodney W. Grimes { 624df8bae1dSRodney W. Grimes struct ifnet *ifp; 625df8bae1dSRodney W. Grimes 626df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 627df8bae1dSRodney W. Grimes error = EINVAL; 628df8bae1dSRodney W. Grimes else { 629df8bae1dSRodney W. Grimes ifp = d->bd_bif->bif_ifp; 630df8bae1dSRodney W. Grimes error = (*ifp->if_ioctl)(ifp, cmd, addr); 631df8bae1dSRodney W. Grimes } 632df8bae1dSRodney W. Grimes break; 633df8bae1dSRodney W. Grimes } 634df8bae1dSRodney W. Grimes 635df8bae1dSRodney W. Grimes /* 636df8bae1dSRodney W. Grimes * Get buffer len [for read()]. 637df8bae1dSRodney W. Grimes */ 638df8bae1dSRodney W. Grimes case BIOCGBLEN: 639df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bufsize; 640df8bae1dSRodney W. Grimes break; 641df8bae1dSRodney W. Grimes 642df8bae1dSRodney W. Grimes /* 643df8bae1dSRodney W. Grimes * Set buffer length. 644df8bae1dSRodney W. Grimes */ 645df8bae1dSRodney W. Grimes case BIOCSBLEN: 646df8bae1dSRodney W. Grimes #if BSD < 199103 647df8bae1dSRodney W. Grimes error = EINVAL; 648df8bae1dSRodney W. Grimes #else 649df8bae1dSRodney W. Grimes if (d->bd_bif != 0) 650df8bae1dSRodney W. Grimes error = EINVAL; 651df8bae1dSRodney W. Grimes else { 652df8bae1dSRodney W. Grimes register u_int size = *(u_int *)addr; 653df8bae1dSRodney W. Grimes 654df8bae1dSRodney W. Grimes if (size > BPF_MAXBUFSIZE) 655df8bae1dSRodney W. Grimes *(u_int *)addr = size = BPF_MAXBUFSIZE; 656df8bae1dSRodney W. Grimes else if (size < BPF_MINBUFSIZE) 657df8bae1dSRodney W. Grimes *(u_int *)addr = size = BPF_MINBUFSIZE; 658df8bae1dSRodney W. Grimes d->bd_bufsize = size; 659df8bae1dSRodney W. Grimes } 660df8bae1dSRodney W. Grimes #endif 661df8bae1dSRodney W. Grimes break; 662df8bae1dSRodney W. Grimes 663df8bae1dSRodney W. Grimes /* 664df8bae1dSRodney W. Grimes * Set link layer read filter. 665df8bae1dSRodney W. Grimes */ 666df8bae1dSRodney W. Grimes case BIOCSETF: 667df8bae1dSRodney W. Grimes error = bpf_setf(d, (struct bpf_program *)addr); 668df8bae1dSRodney W. Grimes break; 669df8bae1dSRodney W. Grimes 670df8bae1dSRodney W. Grimes /* 671df8bae1dSRodney W. Grimes * Flush read packet buffer. 672df8bae1dSRodney W. Grimes */ 673df8bae1dSRodney W. Grimes case BIOCFLUSH: 674df8bae1dSRodney W. Grimes s = splimp(); 675df8bae1dSRodney W. Grimes reset_d(d); 676df8bae1dSRodney W. Grimes splx(s); 677df8bae1dSRodney W. Grimes break; 678df8bae1dSRodney W. Grimes 679df8bae1dSRodney W. Grimes /* 680df8bae1dSRodney W. Grimes * Put interface into promiscuous mode. 681df8bae1dSRodney W. Grimes */ 682df8bae1dSRodney W. Grimes case BIOCPROMISC: 683df8bae1dSRodney W. Grimes if (d->bd_bif == 0) { 684df8bae1dSRodney W. Grimes /* 685df8bae1dSRodney W. Grimes * No interface attached yet. 686df8bae1dSRodney W. Grimes */ 687df8bae1dSRodney W. Grimes error = EINVAL; 688df8bae1dSRodney W. Grimes break; 689df8bae1dSRodney W. Grimes } 690df8bae1dSRodney W. Grimes s = splimp(); 691df8bae1dSRodney W. Grimes if (d->bd_promisc == 0) { 692df8bae1dSRodney W. Grimes error = ifpromisc(d->bd_bif->bif_ifp, 1); 693df8bae1dSRodney W. Grimes if (error == 0) 694df8bae1dSRodney W. Grimes d->bd_promisc = 1; 695df8bae1dSRodney W. Grimes } 696df8bae1dSRodney W. Grimes splx(s); 697df8bae1dSRodney W. Grimes break; 698df8bae1dSRodney W. Grimes 699df8bae1dSRodney W. Grimes /* 700df8bae1dSRodney W. Grimes * Get device parameters. 701df8bae1dSRodney W. Grimes */ 702df8bae1dSRodney W. Grimes case BIOCGDLT: 703df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 704df8bae1dSRodney W. Grimes error = EINVAL; 705df8bae1dSRodney W. Grimes else 706df8bae1dSRodney W. Grimes *(u_int *)addr = d->bd_bif->bif_dlt; 707df8bae1dSRodney W. Grimes break; 708df8bae1dSRodney W. Grimes 709df8bae1dSRodney W. Grimes /* 710df8bae1dSRodney W. Grimes * Set interface name. 711df8bae1dSRodney W. Grimes */ 712df8bae1dSRodney W. Grimes case BIOCGETIF: 713df8bae1dSRodney W. Grimes if (d->bd_bif == 0) 714df8bae1dSRodney W. Grimes error = EINVAL; 715df8bae1dSRodney W. Grimes else 716df8bae1dSRodney W. Grimes bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr); 717df8bae1dSRodney W. Grimes break; 718df8bae1dSRodney W. Grimes 719df8bae1dSRodney W. Grimes /* 720df8bae1dSRodney W. Grimes * Set interface. 721df8bae1dSRodney W. Grimes */ 722df8bae1dSRodney W. Grimes case BIOCSETIF: 723df8bae1dSRodney W. Grimes error = bpf_setif(d, (struct ifreq *)addr); 724df8bae1dSRodney W. Grimes break; 725df8bae1dSRodney W. Grimes 726df8bae1dSRodney W. Grimes /* 727df8bae1dSRodney W. Grimes * Set read timeout. 728df8bae1dSRodney W. Grimes */ 729df8bae1dSRodney W. Grimes case BIOCSRTIMEOUT: 730df8bae1dSRodney W. Grimes { 731df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 732df8bae1dSRodney W. Grimes u_long msec; 733df8bae1dSRodney W. Grimes 734df8bae1dSRodney W. Grimes /* Compute number of milliseconds. */ 735df8bae1dSRodney W. Grimes msec = tv->tv_sec * 1000 + tv->tv_usec / 1000; 736df8bae1dSRodney W. Grimes /* Scale milliseconds to ticks. Assume hard 737df8bae1dSRodney W. Grimes clock has millisecond or greater resolution 738df8bae1dSRodney W. Grimes (i.e. tick >= 1000). For 10ms hardclock, 739df8bae1dSRodney W. Grimes tick/1000 = 10, so rtout<-msec/10. */ 740df8bae1dSRodney W. Grimes d->bd_rtout = msec / (tick / 1000); 741df8bae1dSRodney W. Grimes break; 742df8bae1dSRodney W. Grimes } 743df8bae1dSRodney W. Grimes 744df8bae1dSRodney W. Grimes /* 745df8bae1dSRodney W. Grimes * Get read timeout. 746df8bae1dSRodney W. Grimes */ 747df8bae1dSRodney W. Grimes case BIOCGRTIMEOUT: 748df8bae1dSRodney W. Grimes { 749df8bae1dSRodney W. Grimes struct timeval *tv = (struct timeval *)addr; 750df8bae1dSRodney W. Grimes u_long msec = d->bd_rtout; 751df8bae1dSRodney W. Grimes 752df8bae1dSRodney W. Grimes msec *= tick / 1000; 753df8bae1dSRodney W. Grimes tv->tv_sec = msec / 1000; 754df8bae1dSRodney W. Grimes tv->tv_usec = msec % 1000; 755df8bae1dSRodney W. Grimes break; 756df8bae1dSRodney W. Grimes } 757df8bae1dSRodney W. Grimes 758df8bae1dSRodney W. Grimes /* 759df8bae1dSRodney W. Grimes * Get packet stats. 760df8bae1dSRodney W. Grimes */ 761df8bae1dSRodney W. Grimes case BIOCGSTATS: 762df8bae1dSRodney W. Grimes { 763df8bae1dSRodney W. Grimes struct bpf_stat *bs = (struct bpf_stat *)addr; 764df8bae1dSRodney W. Grimes 765df8bae1dSRodney W. Grimes bs->bs_recv = d->bd_rcount; 766df8bae1dSRodney W. Grimes bs->bs_drop = d->bd_dcount; 767df8bae1dSRodney W. Grimes break; 768df8bae1dSRodney W. Grimes } 769df8bae1dSRodney W. Grimes 770df8bae1dSRodney W. Grimes /* 771df8bae1dSRodney W. Grimes * Set immediate mode. 772df8bae1dSRodney W. Grimes */ 773df8bae1dSRodney W. Grimes case BIOCIMMEDIATE: 774df8bae1dSRodney W. Grimes d->bd_immediate = *(u_int *)addr; 775df8bae1dSRodney W. Grimes break; 776df8bae1dSRodney W. Grimes 777df8bae1dSRodney W. Grimes case BIOCVERSION: 778df8bae1dSRodney W. Grimes { 779df8bae1dSRodney W. Grimes struct bpf_version *bv = (struct bpf_version *)addr; 780df8bae1dSRodney W. Grimes 781df8bae1dSRodney W. Grimes bv->bv_major = BPF_MAJOR_VERSION; 782df8bae1dSRodney W. Grimes bv->bv_minor = BPF_MINOR_VERSION; 783df8bae1dSRodney W. Grimes break; 784df8bae1dSRodney W. Grimes } 785df8bae1dSRodney W. Grimes } 786df8bae1dSRodney W. Grimes return (error); 787df8bae1dSRodney W. Grimes } 788df8bae1dSRodney W. Grimes 789df8bae1dSRodney W. Grimes /* 790df8bae1dSRodney W. Grimes * Set d's packet filter program to fp. If this file already has a filter, 791df8bae1dSRodney W. Grimes * free it and replace it. Returns EINVAL for bogus requests. 792df8bae1dSRodney W. Grimes */ 793df8bae1dSRodney W. Grimes int 794df8bae1dSRodney W. Grimes bpf_setf(d, fp) 795df8bae1dSRodney W. Grimes struct bpf_d *d; 796df8bae1dSRodney W. Grimes struct bpf_program *fp; 797df8bae1dSRodney W. Grimes { 798df8bae1dSRodney W. Grimes struct bpf_insn *fcode, *old; 799df8bae1dSRodney W. Grimes u_int flen, size; 800df8bae1dSRodney W. Grimes int s; 801df8bae1dSRodney W. Grimes 802df8bae1dSRodney W. Grimes old = d->bd_filter; 803df8bae1dSRodney W. Grimes if (fp->bf_insns == 0) { 804df8bae1dSRodney W. Grimes if (fp->bf_len != 0) 805df8bae1dSRodney W. Grimes return (EINVAL); 806df8bae1dSRodney W. Grimes s = splimp(); 807df8bae1dSRodney W. Grimes d->bd_filter = 0; 808df8bae1dSRodney W. Grimes reset_d(d); 809df8bae1dSRodney W. Grimes splx(s); 810df8bae1dSRodney W. Grimes if (old != 0) 811df8bae1dSRodney W. Grimes free((caddr_t)old, M_DEVBUF); 812df8bae1dSRodney W. Grimes return (0); 813df8bae1dSRodney W. Grimes } 814df8bae1dSRodney W. Grimes flen = fp->bf_len; 815df8bae1dSRodney W. Grimes if (flen > BPF_MAXINSNS) 816df8bae1dSRodney W. Grimes return (EINVAL); 817df8bae1dSRodney W. Grimes 818df8bae1dSRodney W. Grimes size = flen * sizeof(*fp->bf_insns); 819df8bae1dSRodney W. Grimes fcode = (struct bpf_insn *)malloc(size, M_DEVBUF, M_WAITOK); 820df8bae1dSRodney W. Grimes if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && 821df8bae1dSRodney W. Grimes bpf_validate(fcode, (int)flen)) { 822df8bae1dSRodney W. Grimes s = splimp(); 823df8bae1dSRodney W. Grimes d->bd_filter = fcode; 824df8bae1dSRodney W. Grimes reset_d(d); 825df8bae1dSRodney W. Grimes splx(s); 826df8bae1dSRodney W. Grimes if (old != 0) 827df8bae1dSRodney W. Grimes free((caddr_t)old, M_DEVBUF); 828df8bae1dSRodney W. Grimes 829df8bae1dSRodney W. Grimes return (0); 830df8bae1dSRodney W. Grimes } 831df8bae1dSRodney W. Grimes free((caddr_t)fcode, M_DEVBUF); 832df8bae1dSRodney W. Grimes return (EINVAL); 833df8bae1dSRodney W. Grimes } 834df8bae1dSRodney W. Grimes 835df8bae1dSRodney W. Grimes /* 836df8bae1dSRodney W. Grimes * Detach a file from its current interface (if attached at all) and attach 837df8bae1dSRodney W. Grimes * to the interface indicated by the name stored in ifr. 838df8bae1dSRodney W. Grimes * Return an errno or 0. 839df8bae1dSRodney W. Grimes */ 840df8bae1dSRodney W. Grimes static int 841df8bae1dSRodney W. Grimes bpf_setif(d, ifr) 842df8bae1dSRodney W. Grimes struct bpf_d *d; 843df8bae1dSRodney W. Grimes struct ifreq *ifr; 844df8bae1dSRodney W. Grimes { 845df8bae1dSRodney W. Grimes struct bpf_if *bp; 846df8bae1dSRodney W. Grimes char *cp; 847df8bae1dSRodney W. Grimes int unit, s, error; 848df8bae1dSRodney W. Grimes 849df8bae1dSRodney W. Grimes /* 850df8bae1dSRodney W. Grimes * Separate string into name part and unit number. Put a null 851df8bae1dSRodney W. Grimes * byte at the end of the name part, and compute the number. 852df8bae1dSRodney W. Grimes * If the a unit number is unspecified, the default is 0, 853df8bae1dSRodney W. Grimes * as initialized above. XXX This should be common code. 854df8bae1dSRodney W. Grimes */ 855df8bae1dSRodney W. Grimes unit = 0; 856df8bae1dSRodney W. Grimes cp = ifr->ifr_name; 857df8bae1dSRodney W. Grimes cp[sizeof(ifr->ifr_name) - 1] = '\0'; 858df8bae1dSRodney W. Grimes while (*cp++) { 859df8bae1dSRodney W. Grimes if (*cp >= '0' && *cp <= '9') { 860df8bae1dSRodney W. Grimes unit = *cp - '0'; 861df8bae1dSRodney W. Grimes *cp++ = '\0'; 862df8bae1dSRodney W. Grimes while (*cp) 863df8bae1dSRodney W. Grimes unit = 10 * unit + *cp++ - '0'; 864df8bae1dSRodney W. Grimes break; 865df8bae1dSRodney W. Grimes } 866df8bae1dSRodney W. Grimes } 867df8bae1dSRodney W. Grimes /* 868df8bae1dSRodney W. Grimes * Look through attached interfaces for the named one. 869df8bae1dSRodney W. Grimes */ 870df8bae1dSRodney W. Grimes for (bp = bpf_iflist; bp != 0; bp = bp->bif_next) { 871df8bae1dSRodney W. Grimes struct ifnet *ifp = bp->bif_ifp; 872df8bae1dSRodney W. Grimes 873df8bae1dSRodney W. Grimes if (ifp == 0 || unit != ifp->if_unit 874df8bae1dSRodney W. Grimes || strcmp(ifp->if_name, ifr->ifr_name) != 0) 875df8bae1dSRodney W. Grimes continue; 876df8bae1dSRodney W. Grimes /* 877df8bae1dSRodney W. Grimes * We found the requested interface. 878df8bae1dSRodney W. Grimes * If it's not up, return an error. 879df8bae1dSRodney W. Grimes * Allocate the packet buffers if we need to. 880df8bae1dSRodney W. Grimes * If we're already attached to requested interface, 881df8bae1dSRodney W. Grimes * just flush the buffer. 882df8bae1dSRodney W. Grimes */ 883df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_UP) == 0) 884df8bae1dSRodney W. Grimes return (ENETDOWN); 885df8bae1dSRodney W. Grimes 886df8bae1dSRodney W. Grimes if (d->bd_sbuf == 0) { 887df8bae1dSRodney W. Grimes error = bpf_allocbufs(d); 888df8bae1dSRodney W. Grimes if (error != 0) 889df8bae1dSRodney W. Grimes return (error); 890df8bae1dSRodney W. Grimes } 891df8bae1dSRodney W. Grimes s = splimp(); 892df8bae1dSRodney W. Grimes if (bp != d->bd_bif) { 893df8bae1dSRodney W. Grimes if (d->bd_bif) 894df8bae1dSRodney W. Grimes /* 895df8bae1dSRodney W. Grimes * Detach if attached to something else. 896df8bae1dSRodney W. Grimes */ 897df8bae1dSRodney W. Grimes bpf_detachd(d); 898df8bae1dSRodney W. Grimes 899df8bae1dSRodney W. Grimes bpf_attachd(d, bp); 900df8bae1dSRodney W. Grimes } 901df8bae1dSRodney W. Grimes reset_d(d); 902df8bae1dSRodney W. Grimes splx(s); 903df8bae1dSRodney W. Grimes return (0); 904df8bae1dSRodney W. Grimes } 905df8bae1dSRodney W. Grimes /* Not found. */ 906df8bae1dSRodney W. Grimes return (ENXIO); 907df8bae1dSRodney W. Grimes } 908df8bae1dSRodney W. Grimes 909df8bae1dSRodney W. Grimes /* 910df8bae1dSRodney W. Grimes * Convert an interface name plus unit number of an ifp to a single 911df8bae1dSRodney W. Grimes * name which is returned in the ifr. 912df8bae1dSRodney W. Grimes */ 913df8bae1dSRodney W. Grimes static void 914df8bae1dSRodney W. Grimes bpf_ifname(ifp, ifr) 915df8bae1dSRodney W. Grimes struct ifnet *ifp; 916df8bae1dSRodney W. Grimes struct ifreq *ifr; 917df8bae1dSRodney W. Grimes { 918df8bae1dSRodney W. Grimes char *s = ifp->if_name; 919df8bae1dSRodney W. Grimes char *d = ifr->ifr_name; 920df8bae1dSRodney W. Grimes 921df8bae1dSRodney W. Grimes while (*d++ = *s++) 922df8bae1dSRodney W. Grimes continue; 923df8bae1dSRodney W. Grimes /* XXX Assume that unit number is less than 10. */ 924df8bae1dSRodney W. Grimes *d++ = ifp->if_unit + '0'; 925df8bae1dSRodney W. Grimes *d = '\0'; 926df8bae1dSRodney W. Grimes } 927df8bae1dSRodney W. Grimes 928df8bae1dSRodney W. Grimes /* 929df8bae1dSRodney W. Grimes * The new select interface passes down the proc pointer; the old select 930df8bae1dSRodney W. Grimes * stubs had to grab it out of the user struct. This glue allows either case. 931df8bae1dSRodney W. Grimes */ 932df8bae1dSRodney W. Grimes #if BSD >= 199103 933df8bae1dSRodney W. Grimes #define bpf_select bpfselect 934df8bae1dSRodney W. Grimes #else 935df8bae1dSRodney W. Grimes int 936df8bae1dSRodney W. Grimes bpfselect(dev, rw) 937df8bae1dSRodney W. Grimes register dev_t dev; 938df8bae1dSRodney W. Grimes int rw; 939df8bae1dSRodney W. Grimes { 940df8bae1dSRodney W. Grimes return (bpf_select(dev, rw, u.u_procp)); 941df8bae1dSRodney W. Grimes } 942df8bae1dSRodney W. Grimes #endif 943df8bae1dSRodney W. Grimes 944df8bae1dSRodney W. Grimes /* 945df8bae1dSRodney W. Grimes * Support for select() system call 946df8bae1dSRodney W. Grimes * 947df8bae1dSRodney W. Grimes * Return true iff the specific operation will not block indefinitely. 948df8bae1dSRodney W. Grimes * Otherwise, return false but make a note that a selwakeup() must be done. 949df8bae1dSRodney W. Grimes */ 950df8bae1dSRodney W. Grimes int 951df8bae1dSRodney W. Grimes bpf_select(dev, rw, p) 952df8bae1dSRodney W. Grimes register dev_t dev; 953df8bae1dSRodney W. Grimes int rw; 954df8bae1dSRodney W. Grimes struct proc *p; 955df8bae1dSRodney W. Grimes { 956df8bae1dSRodney W. Grimes register struct bpf_d *d; 957df8bae1dSRodney W. Grimes register int s; 958df8bae1dSRodney W. Grimes 959df8bae1dSRodney W. Grimes if (rw != FREAD) 960df8bae1dSRodney W. Grimes return (0); 961df8bae1dSRodney W. Grimes /* 962df8bae1dSRodney W. Grimes * An imitation of the FIONREAD ioctl code. 963df8bae1dSRodney W. Grimes */ 964df8bae1dSRodney W. Grimes d = &bpf_dtab[minor(dev)]; 965df8bae1dSRodney W. Grimes 966df8bae1dSRodney W. Grimes s = splimp(); 967df8bae1dSRodney W. Grimes if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0)) { 968df8bae1dSRodney W. Grimes /* 969df8bae1dSRodney W. Grimes * There is data waiting. 970df8bae1dSRodney W. Grimes */ 971df8bae1dSRodney W. Grimes splx(s); 972df8bae1dSRodney W. Grimes return (1); 973df8bae1dSRodney W. Grimes } 974df8bae1dSRodney W. Grimes #if BSD >= 199103 975df8bae1dSRodney W. Grimes selrecord(p, &d->bd_sel); 976df8bae1dSRodney W. Grimes #else 977df8bae1dSRodney W. Grimes /* 978df8bae1dSRodney W. Grimes * No data ready. If there's already a select() waiting on this 979df8bae1dSRodney W. Grimes * minor device then this is a collision. This shouldn't happen 980df8bae1dSRodney W. Grimes * because minors really should not be shared, but if a process 981df8bae1dSRodney W. Grimes * forks while one of these is open, it is possible that both 982df8bae1dSRodney W. Grimes * processes could select on the same descriptor. 983df8bae1dSRodney W. Grimes */ 984df8bae1dSRodney W. Grimes if (d->bd_selproc && d->bd_selproc->p_wchan == (caddr_t)&selwait) 985df8bae1dSRodney W. Grimes d->bd_selcoll = 1; 986df8bae1dSRodney W. Grimes else 987df8bae1dSRodney W. Grimes d->bd_selproc = p; 988df8bae1dSRodney W. Grimes #endif 989df8bae1dSRodney W. Grimes splx(s); 990df8bae1dSRodney W. Grimes return (0); 991df8bae1dSRodney W. Grimes } 992df8bae1dSRodney W. Grimes 993df8bae1dSRodney W. Grimes /* 994df8bae1dSRodney W. Grimes * Incoming linkage from device drivers. Process the packet pkt, of length 995df8bae1dSRodney W. Grimes * pktlen, which is stored in a contiguous buffer. The packet is parsed 996df8bae1dSRodney W. Grimes * by each process' filter, and if accepted, stashed into the corresponding 997df8bae1dSRodney W. Grimes * buffer. 998df8bae1dSRodney W. Grimes */ 999df8bae1dSRodney W. Grimes void 1000df8bae1dSRodney W. Grimes bpf_tap(arg, pkt, pktlen) 1001df8bae1dSRodney W. Grimes caddr_t arg; 1002df8bae1dSRodney W. Grimes register u_char *pkt; 1003df8bae1dSRodney W. Grimes register u_int pktlen; 1004df8bae1dSRodney W. Grimes { 1005df8bae1dSRodney W. Grimes struct bpf_if *bp; 1006df8bae1dSRodney W. Grimes register struct bpf_d *d; 1007df8bae1dSRodney W. Grimes register u_int slen; 1008df8bae1dSRodney W. Grimes /* 1009df8bae1dSRodney W. Grimes * Note that the ipl does not have to be raised at this point. 1010df8bae1dSRodney W. Grimes * The only problem that could arise here is that if two different 1011df8bae1dSRodney W. Grimes * interfaces shared any data. This is not the case. 1012df8bae1dSRodney W. Grimes */ 1013df8bae1dSRodney W. Grimes bp = (struct bpf_if *)arg; 1014df8bae1dSRodney W. Grimes for (d = bp->bif_dlist; d != 0; d = d->bd_next) { 1015df8bae1dSRodney W. Grimes ++d->bd_rcount; 1016df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen); 1017df8bae1dSRodney W. Grimes if (slen != 0) 1018df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, slen, bcopy); 1019df8bae1dSRodney W. Grimes } 1020df8bae1dSRodney W. Grimes } 1021df8bae1dSRodney W. Grimes 1022df8bae1dSRodney W. Grimes /* 1023df8bae1dSRodney W. Grimes * Copy data from an mbuf chain into a buffer. This code is derived 1024df8bae1dSRodney W. Grimes * from m_copydata in sys/uipc_mbuf.c. 1025df8bae1dSRodney W. Grimes */ 1026df8bae1dSRodney W. Grimes static void 1027df8bae1dSRodney W. Grimes bpf_mcopy(src_arg, dst_arg, len) 1028df8bae1dSRodney W. Grimes const void *src_arg; 1029df8bae1dSRodney W. Grimes void *dst_arg; 1030df8bae1dSRodney W. Grimes register u_int len; 1031df8bae1dSRodney W. Grimes { 1032df8bae1dSRodney W. Grimes register const struct mbuf *m; 1033df8bae1dSRodney W. Grimes register u_int count; 1034df8bae1dSRodney W. Grimes u_char *dst; 1035df8bae1dSRodney W. Grimes 1036df8bae1dSRodney W. Grimes m = src_arg; 1037df8bae1dSRodney W. Grimes dst = dst_arg; 1038df8bae1dSRodney W. Grimes while (len > 0) { 1039df8bae1dSRodney W. Grimes if (m == 0) 1040df8bae1dSRodney W. Grimes panic("bpf_mcopy"); 1041df8bae1dSRodney W. Grimes count = min(m->m_len, len); 1042df8bae1dSRodney W. Grimes bcopy(mtod(m, caddr_t), (caddr_t)dst, count); 1043df8bae1dSRodney W. Grimes m = m->m_next; 1044df8bae1dSRodney W. Grimes dst += count; 1045df8bae1dSRodney W. Grimes len -= count; 1046df8bae1dSRodney W. Grimes } 1047df8bae1dSRodney W. Grimes } 1048df8bae1dSRodney W. Grimes 1049df8bae1dSRodney W. Grimes /* 1050df8bae1dSRodney W. Grimes * Incoming linkage from device drivers, when packet is in an mbuf chain. 1051df8bae1dSRodney W. Grimes */ 1052df8bae1dSRodney W. Grimes void 1053df8bae1dSRodney W. Grimes bpf_mtap(arg, m) 1054df8bae1dSRodney W. Grimes caddr_t arg; 1055df8bae1dSRodney W. Grimes struct mbuf *m; 1056df8bae1dSRodney W. Grimes { 1057df8bae1dSRodney W. Grimes struct bpf_if *bp = (struct bpf_if *)arg; 1058df8bae1dSRodney W. Grimes struct bpf_d *d; 1059df8bae1dSRodney W. Grimes u_int pktlen, slen; 1060df8bae1dSRodney W. Grimes struct mbuf *m0; 1061df8bae1dSRodney W. Grimes 1062df8bae1dSRodney W. Grimes pktlen = 0; 1063df8bae1dSRodney W. Grimes for (m0 = m; m0 != 0; m0 = m0->m_next) 1064df8bae1dSRodney W. Grimes pktlen += m0->m_len; 1065df8bae1dSRodney W. Grimes 1066df8bae1dSRodney W. Grimes for (d = bp->bif_dlist; d != 0; d = d->bd_next) { 1067df8bae1dSRodney W. Grimes ++d->bd_rcount; 1068df8bae1dSRodney W. Grimes slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0); 1069df8bae1dSRodney W. Grimes if (slen != 0) 1070df8bae1dSRodney W. Grimes catchpacket(d, (u_char *)m, pktlen, slen, bpf_mcopy); 1071df8bae1dSRodney W. Grimes } 1072df8bae1dSRodney W. Grimes } 1073df8bae1dSRodney W. Grimes 1074df8bae1dSRodney W. Grimes /* 1075df8bae1dSRodney W. Grimes * Move the packet data from interface memory (pkt) into the 1076df8bae1dSRodney W. Grimes * store buffer. Return 1 if it's time to wakeup a listener (buffer full), 1077df8bae1dSRodney W. Grimes * otherwise 0. "copy" is the routine called to do the actual data 1078df8bae1dSRodney W. Grimes * transfer. bcopy is passed in to copy contiguous chunks, while 1079df8bae1dSRodney W. Grimes * bpf_mcopy is passed in to copy mbuf chains. In the latter case, 1080df8bae1dSRodney W. Grimes * pkt is really an mbuf. 1081df8bae1dSRodney W. Grimes */ 1082df8bae1dSRodney W. Grimes static void 1083df8bae1dSRodney W. Grimes catchpacket(d, pkt, pktlen, snaplen, cpfn) 1084df8bae1dSRodney W. Grimes register struct bpf_d *d; 1085df8bae1dSRodney W. Grimes register u_char *pkt; 1086df8bae1dSRodney W. Grimes register u_int pktlen, snaplen; 1087df8bae1dSRodney W. Grimes register void (*cpfn)(const void *, void *, u_int); 1088df8bae1dSRodney W. Grimes { 1089df8bae1dSRodney W. Grimes register struct bpf_hdr *hp; 1090df8bae1dSRodney W. Grimes register int totlen, curlen; 1091df8bae1dSRodney W. Grimes register int hdrlen = d->bd_bif->bif_hdrlen; 1092df8bae1dSRodney W. Grimes /* 1093df8bae1dSRodney W. Grimes * Figure out how many bytes to move. If the packet is 1094df8bae1dSRodney W. Grimes * greater or equal to the snapshot length, transfer that 1095df8bae1dSRodney W. Grimes * much. Otherwise, transfer the whole packet (unless 1096df8bae1dSRodney W. Grimes * we hit the buffer size limit). 1097df8bae1dSRodney W. Grimes */ 1098df8bae1dSRodney W. Grimes totlen = hdrlen + min(snaplen, pktlen); 1099df8bae1dSRodney W. Grimes if (totlen > d->bd_bufsize) 1100df8bae1dSRodney W. Grimes totlen = d->bd_bufsize; 1101df8bae1dSRodney W. Grimes 1102df8bae1dSRodney W. Grimes /* 1103df8bae1dSRodney W. Grimes * Round up the end of the previous packet to the next longword. 1104df8bae1dSRodney W. Grimes */ 1105df8bae1dSRodney W. Grimes curlen = BPF_WORDALIGN(d->bd_slen); 1106df8bae1dSRodney W. Grimes if (curlen + totlen > d->bd_bufsize) { 1107df8bae1dSRodney W. Grimes /* 1108df8bae1dSRodney W. Grimes * This packet will overflow the storage buffer. 1109df8bae1dSRodney W. Grimes * Rotate the buffers if we can, then wakeup any 1110df8bae1dSRodney W. Grimes * pending reads. 1111df8bae1dSRodney W. Grimes */ 1112df8bae1dSRodney W. Grimes if (d->bd_fbuf == 0) { 1113df8bae1dSRodney W. Grimes /* 1114df8bae1dSRodney W. Grimes * We haven't completed the previous read yet, 1115df8bae1dSRodney W. Grimes * so drop the packet. 1116df8bae1dSRodney W. Grimes */ 1117df8bae1dSRodney W. Grimes ++d->bd_dcount; 1118df8bae1dSRodney W. Grimes return; 1119df8bae1dSRodney W. Grimes } 1120df8bae1dSRodney W. Grimes ROTATE_BUFFERS(d); 1121df8bae1dSRodney W. Grimes bpf_wakeup(d); 1122df8bae1dSRodney W. Grimes curlen = 0; 1123df8bae1dSRodney W. Grimes } 1124df8bae1dSRodney W. Grimes else if (d->bd_immediate) 1125df8bae1dSRodney W. Grimes /* 1126df8bae1dSRodney W. Grimes * Immediate mode is set. A packet arrived so any 1127df8bae1dSRodney W. Grimes * reads should be woken up. 1128df8bae1dSRodney W. Grimes */ 1129df8bae1dSRodney W. Grimes bpf_wakeup(d); 1130df8bae1dSRodney W. Grimes 1131df8bae1dSRodney W. Grimes /* 1132df8bae1dSRodney W. Grimes * Append the bpf header. 1133df8bae1dSRodney W. Grimes */ 1134df8bae1dSRodney W. Grimes hp = (struct bpf_hdr *)(d->bd_sbuf + curlen); 1135df8bae1dSRodney W. Grimes #if BSD >= 199103 1136df8bae1dSRodney W. Grimes microtime(&hp->bh_tstamp); 1137df8bae1dSRodney W. Grimes #elif defined(sun) 1138df8bae1dSRodney W. Grimes uniqtime(&hp->bh_tstamp); 1139df8bae1dSRodney W. Grimes #else 1140df8bae1dSRodney W. Grimes hp->bh_tstamp = time; 1141df8bae1dSRodney W. Grimes #endif 1142df8bae1dSRodney W. Grimes hp->bh_datalen = pktlen; 1143df8bae1dSRodney W. Grimes hp->bh_hdrlen = hdrlen; 1144df8bae1dSRodney W. Grimes /* 1145df8bae1dSRodney W. Grimes * Copy the packet data into the store buffer and update its length. 1146df8bae1dSRodney W. Grimes */ 1147df8bae1dSRodney W. Grimes (*cpfn)(pkt, (u_char *)hp + hdrlen, (hp->bh_caplen = totlen - hdrlen)); 1148df8bae1dSRodney W. Grimes d->bd_slen = curlen + totlen; 1149df8bae1dSRodney W. Grimes } 1150df8bae1dSRodney W. Grimes 1151df8bae1dSRodney W. Grimes /* 1152df8bae1dSRodney W. Grimes * Initialize all nonzero fields of a descriptor. 1153df8bae1dSRodney W. Grimes */ 1154df8bae1dSRodney W. Grimes static int 1155df8bae1dSRodney W. Grimes bpf_allocbufs(d) 1156df8bae1dSRodney W. Grimes register struct bpf_d *d; 1157df8bae1dSRodney W. Grimes { 1158df8bae1dSRodney W. Grimes d->bd_fbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); 1159df8bae1dSRodney W. Grimes if (d->bd_fbuf == 0) 1160df8bae1dSRodney W. Grimes return (ENOBUFS); 1161df8bae1dSRodney W. Grimes 1162df8bae1dSRodney W. Grimes d->bd_sbuf = (caddr_t)malloc(d->bd_bufsize, M_DEVBUF, M_WAITOK); 1163df8bae1dSRodney W. Grimes if (d->bd_sbuf == 0) { 1164df8bae1dSRodney W. Grimes free(d->bd_fbuf, M_DEVBUF); 1165df8bae1dSRodney W. Grimes return (ENOBUFS); 1166df8bae1dSRodney W. Grimes } 1167df8bae1dSRodney W. Grimes d->bd_slen = 0; 1168df8bae1dSRodney W. Grimes d->bd_hlen = 0; 1169df8bae1dSRodney W. Grimes return (0); 1170df8bae1dSRodney W. Grimes } 1171df8bae1dSRodney W. Grimes 1172df8bae1dSRodney W. Grimes /* 1173df8bae1dSRodney W. Grimes * Free buffers currently in use by a descriptor. 1174df8bae1dSRodney W. Grimes * Called on close. 1175df8bae1dSRodney W. Grimes */ 1176df8bae1dSRodney W. Grimes static void 1177df8bae1dSRodney W. Grimes bpf_freed(d) 1178df8bae1dSRodney W. Grimes register struct bpf_d *d; 1179df8bae1dSRodney W. Grimes { 1180df8bae1dSRodney W. Grimes /* 1181df8bae1dSRodney W. Grimes * We don't need to lock out interrupts since this descriptor has 1182df8bae1dSRodney W. Grimes * been detached from its interface and it yet hasn't been marked 1183df8bae1dSRodney W. Grimes * free. 1184df8bae1dSRodney W. Grimes */ 1185df8bae1dSRodney W. Grimes if (d->bd_sbuf != 0) { 1186df8bae1dSRodney W. Grimes free(d->bd_sbuf, M_DEVBUF); 1187df8bae1dSRodney W. Grimes if (d->bd_hbuf != 0) 1188df8bae1dSRodney W. Grimes free(d->bd_hbuf, M_DEVBUF); 1189df8bae1dSRodney W. Grimes if (d->bd_fbuf != 0) 1190df8bae1dSRodney W. Grimes free(d->bd_fbuf, M_DEVBUF); 1191df8bae1dSRodney W. Grimes } 1192df8bae1dSRodney W. Grimes if (d->bd_filter) 1193df8bae1dSRodney W. Grimes free((caddr_t)d->bd_filter, M_DEVBUF); 1194df8bae1dSRodney W. Grimes 1195df8bae1dSRodney W. Grimes D_MARKFREE(d); 1196df8bae1dSRodney W. Grimes } 1197df8bae1dSRodney W. Grimes 1198df8bae1dSRodney W. Grimes /* 1199df8bae1dSRodney W. Grimes * Attach an interface to bpf. driverp is a pointer to a (struct bpf_if *) 1200df8bae1dSRodney W. Grimes * in the driver's softc; dlt is the link layer type; hdrlen is the fixed 1201df8bae1dSRodney W. Grimes * size of the link header (variable length headers not yet supported). 1202df8bae1dSRodney W. Grimes */ 1203df8bae1dSRodney W. Grimes void 1204df8bae1dSRodney W. Grimes bpfattach(driverp, ifp, dlt, hdrlen) 1205df8bae1dSRodney W. Grimes caddr_t *driverp; 1206df8bae1dSRodney W. Grimes struct ifnet *ifp; 1207df8bae1dSRodney W. Grimes u_int dlt, hdrlen; 1208df8bae1dSRodney W. Grimes { 1209df8bae1dSRodney W. Grimes struct bpf_if *bp; 1210df8bae1dSRodney W. Grimes int i; 1211df8bae1dSRodney W. Grimes #if BSD < 199103 1212df8bae1dSRodney W. Grimes static struct bpf_if bpf_ifs[NBPFILTER]; 1213df8bae1dSRodney W. Grimes static int bpfifno; 1214df8bae1dSRodney W. Grimes 1215df8bae1dSRodney W. Grimes bp = (bpfifno < NBPFILTER) ? &bpf_ifs[bpfifno++] : 0; 1216df8bae1dSRodney W. Grimes #else 1217df8bae1dSRodney W. Grimes bp = (struct bpf_if *)malloc(sizeof(*bp), M_DEVBUF, M_DONTWAIT); 1218df8bae1dSRodney W. Grimes #endif 1219df8bae1dSRodney W. Grimes if (bp == 0) 1220df8bae1dSRodney W. Grimes panic("bpfattach"); 1221df8bae1dSRodney W. Grimes 1222df8bae1dSRodney W. Grimes bp->bif_dlist = 0; 1223df8bae1dSRodney W. Grimes bp->bif_driverp = (struct bpf_if **)driverp; 1224df8bae1dSRodney W. Grimes bp->bif_ifp = ifp; 1225df8bae1dSRodney W. Grimes bp->bif_dlt = dlt; 1226df8bae1dSRodney W. Grimes 1227df8bae1dSRodney W. Grimes bp->bif_next = bpf_iflist; 1228df8bae1dSRodney W. Grimes bpf_iflist = bp; 1229df8bae1dSRodney W. Grimes 1230df8bae1dSRodney W. Grimes *bp->bif_driverp = 0; 1231df8bae1dSRodney W. Grimes 1232df8bae1dSRodney W. Grimes /* 1233df8bae1dSRodney W. Grimes * Compute the length of the bpf header. This is not necessarily 1234df8bae1dSRodney W. Grimes * equal to SIZEOF_BPF_HDR because we want to insert spacing such 1235df8bae1dSRodney W. Grimes * that the network layer header begins on a longword boundary (for 1236df8bae1dSRodney W. Grimes * performance reasons and to alleviate alignment restrictions). 1237df8bae1dSRodney W. Grimes */ 1238df8bae1dSRodney W. Grimes bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen; 1239df8bae1dSRodney W. Grimes 1240df8bae1dSRodney W. Grimes /* 1241df8bae1dSRodney W. Grimes * Mark all the descriptors free if this hasn't been done. 1242df8bae1dSRodney W. Grimes */ 1243df8bae1dSRodney W. Grimes if (!D_ISFREE(&bpf_dtab[0])) 1244df8bae1dSRodney W. Grimes for (i = 0; i < NBPFILTER; ++i) 1245df8bae1dSRodney W. Grimes D_MARKFREE(&bpf_dtab[i]); 1246df8bae1dSRodney W. Grimes 1247df8bae1dSRodney W. Grimes printf("bpf: %s%d attached\n", ifp->if_name, ifp->if_unit); 1248df8bae1dSRodney W. Grimes } 1249df8bae1dSRodney W. Grimes 1250df8bae1dSRodney W. Grimes #if BSD >= 199103 1251df8bae1dSRodney W. Grimes /* XXX This routine belongs in net/if.c. */ 1252df8bae1dSRodney W. Grimes /* 1253df8bae1dSRodney W. Grimes * Set/clear promiscuous mode on interface ifp based on the truth value 1254df8bae1dSRodney W. Grimes * of pswitch. The calls are reference counted so that only the first 1255df8bae1dSRodney W. Grimes * "on" request actually has an effect, as does the final "off" request. 1256df8bae1dSRodney W. Grimes * Results are undefined if the "off" and "on" requests are not matched. 1257df8bae1dSRodney W. Grimes */ 1258df8bae1dSRodney W. Grimes int 1259df8bae1dSRodney W. Grimes ifpromisc(ifp, pswitch) 1260df8bae1dSRodney W. Grimes struct ifnet *ifp; 1261df8bae1dSRodney W. Grimes int pswitch; 1262df8bae1dSRodney W. Grimes { 1263df8bae1dSRodney W. Grimes struct ifreq ifr; 1264df8bae1dSRodney W. Grimes /* 1265df8bae1dSRodney W. Grimes * If the device is not configured up, we cannot put it in 1266df8bae1dSRodney W. Grimes * promiscuous mode. 1267df8bae1dSRodney W. Grimes */ 1268df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_UP) == 0) 1269df8bae1dSRodney W. Grimes return (ENETDOWN); 1270df8bae1dSRodney W. Grimes 1271df8bae1dSRodney W. Grimes if (pswitch) { 1272df8bae1dSRodney W. Grimes if (ifp->if_pcount++ != 0) 1273df8bae1dSRodney W. Grimes return (0); 1274df8bae1dSRodney W. Grimes ifp->if_flags |= IFF_PROMISC; 1275df8bae1dSRodney W. Grimes } else { 1276df8bae1dSRodney W. Grimes if (--ifp->if_pcount > 0) 1277df8bae1dSRodney W. Grimes return (0); 1278df8bae1dSRodney W. Grimes ifp->if_flags &= ~IFF_PROMISC; 1279df8bae1dSRodney W. Grimes } 1280df8bae1dSRodney W. Grimes ifr.ifr_flags = ifp->if_flags; 1281df8bae1dSRodney W. Grimes return ((*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr)); 1282df8bae1dSRodney W. Grimes } 1283df8bae1dSRodney W. Grimes #endif 1284df8bae1dSRodney W. Grimes 1285df8bae1dSRodney W. Grimes #if BSD < 199103 1286df8bae1dSRodney W. Grimes /* 1287df8bae1dSRodney W. Grimes * Allocate some memory for bpf. This is temporary SunOS support, and 1288df8bae1dSRodney W. Grimes * is admittedly a hack. 1289df8bae1dSRodney W. Grimes * If resources unavaiable, return 0. 1290df8bae1dSRodney W. Grimes */ 1291df8bae1dSRodney W. Grimes static caddr_t 1292df8bae1dSRodney W. Grimes bpf_alloc(size, canwait) 1293df8bae1dSRodney W. Grimes register int size; 1294df8bae1dSRodney W. Grimes register int canwait; 1295df8bae1dSRodney W. Grimes { 1296df8bae1dSRodney W. Grimes register struct mbuf *m; 1297df8bae1dSRodney W. Grimes 1298df8bae1dSRodney W. Grimes if ((unsigned)size > (MCLBYTES-8)) 1299df8bae1dSRodney W. Grimes return 0; 1300df8bae1dSRodney W. Grimes 1301df8bae1dSRodney W. Grimes MGET(m, canwait, MT_DATA); 1302df8bae1dSRodney W. Grimes if (m == 0) 1303df8bae1dSRodney W. Grimes return 0; 1304df8bae1dSRodney W. Grimes if ((unsigned)size > (MLEN-8)) { 1305df8bae1dSRodney W. Grimes MCLGET(m); 1306df8bae1dSRodney W. Grimes if (m->m_len != MCLBYTES) { 1307df8bae1dSRodney W. Grimes m_freem(m); 1308df8bae1dSRodney W. Grimes return 0; 1309df8bae1dSRodney W. Grimes } 1310df8bae1dSRodney W. Grimes } 1311df8bae1dSRodney W. Grimes *mtod(m, struct mbuf **) = m; 1312df8bae1dSRodney W. Grimes return mtod(m, caddr_t) + 8; 1313df8bae1dSRodney W. Grimes } 1314df8bae1dSRodney W. Grimes #endif 1315df8bae1dSRodney W. Grimes #endif 1316