xref: /freebsd/sys/net/bpf.c (revision 0310c19f5d0c65dda76b09b3b2940f7c5ad5fd99)
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