⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bpf.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1990, 1991, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence  * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *      @(#)bpf.c	8.2 (Berkeley) 3/28/94 * * static char rcsid[] = * "$Header: bpf.c,v 1.33 91/10/27 21:21:58 mccanne Exp $"; */#include "bpfilter.h"#if NBPFILTER > 0#ifndef __GNUC__#define inline#else#define inline __inline#endif#include <sys/param.h>#include <sys/systm.h>#include <sys/mbuf.h>#include <sys/buf.h>#include <sys/time.h>#include <sys/proc.h>#include <sys/user.h>#include <sys/ioctl.h>#include <sys/map.h>#include <sys/file.h>#if defined(sparc) && BSD < 199103#include <sys/stream.h>#endif#include <sys/tty.h>#include <sys/uio.h>#include <sys/protosw.h>#include <sys/socket.h>#include <net/if.h>#include <net/bpf.h>#include <net/bpfdesc.h>#include <sys/errno.h>#include <netinet/in.h>#include <netinet/if_ether.h>#include <sys/kernel.h>/* * Older BSDs don't have kernel malloc. */#if BSD < 199103extern bcopy();static caddr_t bpf_alloc();#include <net/bpf_compat.h>#define BPF_BUFSIZE (MCLBYTES-8)#define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio)#else#define BPF_BUFSIZE 4096#define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio)#endif#define PRINET  26			/* interruptible *//* * The default read buffer size is patchable. */int bpf_bufsize = BPF_BUFSIZE;/* *  bpf_iflist is the list of interfaces; each corresponds to an ifnet *  bpf_dtab holds the descriptors, indexed by minor device # */struct bpf_if	*bpf_iflist;struct bpf_d	bpf_dtab[NBPFILTER];#if BSD >= 199207/* * bpfilterattach() is called at boot time in new systems.  We do * nothing here since old systems will not call this. *//* ARGSUSED */voidbpfilterattach(n)	int n;{}#endifstatic int	bpf_allocbufs __P((struct bpf_d *));static int	bpf_allocbufs __P((struct bpf_d *));static void	bpf_freed __P((struct bpf_d *));static void	bpf_freed __P((struct bpf_d *));static void	bpf_ifname __P((struct ifnet *, struct ifreq *));static void	bpf_ifname __P((struct ifnet *, struct ifreq *));static void	bpf_mcopy __P((const void *, void *, u_int));static int	bpf_movein __P((struct uio *, int,		    struct mbuf **, struct sockaddr *, int *));static int	bpf_setif __P((struct bpf_d *, struct ifreq *));static int	bpf_setif __P((struct bpf_d *, struct ifreq *));static inline void		bpf_wakeup __P((struct bpf_d *));static void	catchpacket __P((struct bpf_d *, u_char *, u_int,		    u_int, void (*)(const void *, void *, u_int)));static void	reset_d __P((struct bpf_d *));static intbpf_movein(uio, linktype, mp, sockp, datlen)	register struct uio *uio;	int linktype, *datlen;	register struct mbuf **mp;	register struct sockaddr *sockp;{	struct mbuf *m;	int error;	int len;	int hlen;	/*	 * Build a sockaddr based on the data link layer type.	 * We do this at this level because the ethernet header	 * is copied directly into the data field of the sockaddr.	 * In the case of SLIP, there is no header and the packet	 * is forwarded as is.	 * Also, we are careful to leave room at the front of the mbuf	 * for the link level header.	 */	switch (linktype) {	case DLT_SLIP:		sockp->sa_family = AF_INET;		hlen = 0;		break;	case DLT_EN10MB:		sockp->sa_family = AF_UNSPEC;		/* XXX Would MAXLINKHDR be better? */		hlen = sizeof(struct ether_header);		break;	case DLT_FDDI:		sockp->sa_family = AF_UNSPEC;		/* XXX 4(FORMAC)+6(dst)+6(src)+3(LLC)+5(SNAP) */		hlen = 24;		break;	case DLT_NULL:		sockp->sa_family = AF_UNSPEC;		hlen = 0;		break;	default:		return (EIO);	}	len = uio->uio_resid;	*datlen = len - hlen;	if ((unsigned)len > MCLBYTES)		return (EIO);	MGET(m, M_WAIT, MT_DATA);	if (m == 0)		return (ENOBUFS);	if (len > MLEN) {#if BSD >= 199103		MCLGET(m, M_WAIT);		if ((m->m_flags & M_EXT) == 0) {#else		MCLGET(m);		if (m->m_len != MCLBYTES) {#endif			error = ENOBUFS;			goto bad;		}	}	m->m_len = len;	*mp = m;	/*	 * Make room for link header.	 */	if (hlen != 0) {		m->m_len -= hlen;#if BSD >= 199103		m->m_data += hlen; /* XXX */#else		m->m_off += hlen;#endif		error = UIOMOVE((caddr_t)sockp->sa_data, hlen, UIO_WRITE, uio);		if (error)			goto bad;	}	error = UIOMOVE(mtod(m, caddr_t), len - hlen, UIO_WRITE, uio);	if (!error)		return (0); bad:	m_freem(m);	return (error);}/* * Attach file to the bpf interface, i.e. make d listen on bp. * Must be called at splimp. */static voidbpf_attachd(d, bp)	struct bpf_d *d;	struct bpf_if *bp;{	/*	 * Point d at bp, and add d to the interface's list of listeners.	 * Finally, point the driver's bpf cookie at the interface so	 * it will divert packets to bpf.	 */	d->bd_bif = bp;	d->bd_next = bp->bif_dlist;	bp->bif_dlist = d;	*bp->bif_driverp = bp;}/* * Detach a file from its interface. */static voidbpf_detachd(d)	struct bpf_d *d;{	struct bpf_d **p;	struct bpf_if *bp;	bp = d->bd_bif;	/*	 * Check if this descriptor had requested promiscuous mode.	 * If so, turn it off.	 */	if (d->bd_promisc) {		d->bd_promisc = 0;		if (ifpromisc(bp->bif_ifp, 0))			/*			 * Something is really wrong if we were able to put			 * the driver into promiscuous mode, but can't			 * take it out.			 */			panic("bpf: ifpromisc failed");	}	/* Remove d from the interface's descriptor list. */	p = &bp->bif_dlist;	while (*p != d) {		p = &(*p)->bd_next;		if (*p == 0)			panic("bpf_detachd: descriptor not in list");	}	*p = (*p)->bd_next;	if (bp->bif_dlist == 0)		/*		 * Let the driver know that there are no more listeners.		 */		*d->bd_bif->bif_driverp = 0;	d->bd_bif = 0;}/* * Mark a descriptor free by making it point to itself. * This is probably cheaper than marking with a constant since * the address should be in a register anyway. */#define D_ISFREE(d) ((d) == (d)->bd_next)#define D_MARKFREE(d) ((d)->bd_next = (d))#define D_MARKUSED(d) ((d)->bd_next = 0)/* * Open ethernet device.  Returns ENXIO for illegal minor device number, * EBUSY if file is open by another process. *//* ARGSUSED */intbpfopen(dev, flag)	dev_t dev;	int flag;{	register struct bpf_d *d;	if (minor(dev) >= NBPFILTER)		return (ENXIO);	/*	 * Each minor can be opened by only one process.  If the requested	 * minor is in use, return EBUSY.	 */	d = &bpf_dtab[minor(dev)];	if (!D_ISFREE(d))		return (EBUSY);	/* Mark "free" and do most initialization. */	bzero((char *)d, sizeof(*d));	d->bd_bufsize = bpf_bufsize;	return (0);}/* * Close the descriptor by detaching it from its interface, * deallocating its buffers, and marking it free. *//* ARGSUSED */intbpfclose(dev, flag)	dev_t dev;	int flag;{	register struct bpf_d *d = &bpf_dtab[minor(dev)];	register int s;	s = splimp();	if (d->bd_bif)		bpf_detachd(d);	splx(s);	bpf_freed(d);	return (0);}/* * Support for SunOS, which does not have tsleep. */#if BSD < 199103staticbpf_timeout(arg)	caddr_t arg;{	struct bpf_d *d = (struct bpf_d *)arg;	d->bd_timedout = 1;	wakeup(arg);}#define BPF_SLEEP(chan, pri, s, t) bpf_sleep((struct bpf_d *)chan)intbpf_sleep(d)	register struct bpf_d *d;{	register int rto = d->bd_rtout;	register int st;	if (rto != 0) {		d->bd_timedout = 0;		timeout(bpf_timeout, (caddr_t)d, rto);	}	st = sleep((caddr_t)d, PRINET|PCATCH);	if (rto != 0) {		if (d->bd_timedout == 0)			untimeout(bpf_timeout, (caddr_t)d);		else if (st == 0)			return EWOULDBLOCK;	}	return (st != 0) ? EINTR : 0;}#else#define BPF_SLEEP tsleep#endif/* * Rotate the packet buffers in descriptor d.  Move the store buffer * into the hold slot, and the free buffer into the store slot. * Zero the length of the new store buffer. */#define ROTATE_BUFFERS(d) \	(d)->bd_hbuf = (d)->bd_sbuf; \	(d)->bd_hlen = (d)->bd_slen; \	(d)->bd_sbuf = (d)->bd_fbuf; \	(d)->bd_slen = 0; \	(d)->bd_fbuf = 0;/* *  bpfread - read next chunk of packets from buffers */intbpfread(dev, uio)	dev_t dev;	register struct uio *uio;{	register struct bpf_d *d = &bpf_dtab[minor(dev)];	int error;	int s;	/*	 * Restrict application to use a buffer the same size as	 * as kernel buffers.	 */	if (uio->uio_resid != d->bd_bufsize)		return (EINVAL);	s = splimp();	/*	 * If the hold buffer is empty, then do a timed sleep, which	 * ends when the timeout expires or when enough packets	 * have arrived to fill the store buffer.	 */	while (d->bd_hbuf == 0) {		if (d->bd_immediate && d->bd_slen != 0) {			/*			 * A packet(s) either arrived since the previous			 * read or arrived while we were asleep.			 * Rotate the buffers and return what's here.			 */			ROTATE_BUFFERS(d);			break;		}		error = BPF_SLEEP((caddr_t)d, PRINET|PCATCH, "bpf",				  d->bd_rtout);		if (error == EINTR || error == ERESTART) {			splx(s);			return (error);		}		if (error == EWOULDBLOCK) {			/*			 * On a timeout, return what's in the buffer,			 * which may be nothing.  If there is something			 * in the store buffer, we can rotate the buffers.			 */			if (d->bd_hbuf)				/*				 * We filled up the buffer in between				 * getting the timeout and arriving				 * here, so we don't need to rotate.				 */				break;			if (d->bd_slen == 0) {				splx(s);				return (0);			}			ROTATE_BUFFERS(d);			break;		}	}	/*	 * At this point, we know we have something in the hold slot.	 */	splx(s);	/*	 * Move data from hold buffer into user space.	 * We know the entire buffer is transferred since	 * we checked above that the read buffer is bpf_bufsize bytes.	 */	error = UIOMOVE(d->bd_hbuf, d->bd_hlen, UIO_READ, uio);	s = splimp();	d->bd_fbuf = d->bd_hbuf;	d->bd_hbuf = 0;	d->bd_hlen = 0;	splx(s);	return (error);}/* * If there are processes sleeping on this descriptor, wake them up. */static inline voidbpf_wakeup(d)	register struct bpf_d *d;{	wakeup((caddr_t)d);#if BSD >= 199103	selwakeup(&d->bd_sel);	/* XXX */	d->bd_sel.si_pid = 0;#else	if (d->bd_selproc) {		selwakeup(d->bd_selproc, (int)d->bd_selcoll);		d->bd_selcoll = 0;		d->bd_selproc = 0;	}#endif}intbpfwrite(dev, uio)	dev_t dev;	struct uio *uio;{	register struct bpf_d *d = &bpf_dtab[minor(dev)];	struct ifnet *ifp;	struct mbuf *m;	int error, s;	static struct sockaddr dst;	int datlen;	if (d->bd_bif == 0)		return (ENXIO);	ifp = d->bd_bif->bif_ifp;	if (uio->uio_resid == 0)		return (0);	error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, &m, &dst, &datlen);	if (error)		return (error);	if (datlen > ifp->if_mtu)		return (EMSGSIZE);	s = splnet();#if BSD >= 199103	error = (*ifp->if_output)(ifp, m, &dst, (struct rtentry *)0);#else	error = (*ifp->if_output)(ifp, m, &dst);#endif	splx(s);	/*	 * The driver frees the mbuf.	 */	return (error);}/* * Reset a descriptor by flushing its packet buffer and clearing the * receive and drop counts.  Should be called at splimp. */static voidreset_d(d)	struct bpf_d *d;{	if (d->bd_hbuf) {		/* Free the hold buffer. */		d->bd_fbuf = d->bd_hbuf;		d->bd_hbuf = 0;	}	d->bd_slen = 0;	d->bd_hlen = 0;	d->bd_rcount = 0;	d->bd_dcount = 0;}/* *  FIONREAD		Check for read packet available. *  SIOCGIFADDR		Get interface address - convenient hook to driver. *  BIOCGBLEN		Get buffer len [for read()]. *  BIOCSETF		Set ethernet read filter. *  BIOCFLUSH		Flush read packet buffer. *  BIOCPROMISC		Put interface into promiscuous mode. *  BIOCGDLT		Get link layer type. *  BIOCGETIF		Get interface name. *  BIOCSETIF		Set interface. *  BIOCSRTIMEOUT	Set read timeout. *  BIOCGRTIMEOUT	Get read timeout. *  BIOCGSTATS		Get packet stats. *  BIOCIMMEDIATE	Set immediate mode. *  BIOCVERSION		Get filter language version. *//* ARGSUSED */intbpfioctl(dev, cmd, addr, flag)	dev_t dev;	int cmd;	caddr_t addr;	int flag;{	register struct bpf_d *d = &bpf_dtab[minor(dev)];	int s, error = 0;	switch (cmd) {	default:		error = EINVAL;		break;	/*	 * Check for read packet available.	 */	case FIONREAD:		{			int n;			s = splimp();			n = d->bd_slen;			if (d->bd_hbuf)				n += d->bd_hlen;			splx(s);			*(int *)addr = n;			break;		}	case SIOCGIFADDR:		{			struct ifnet *ifp;			if (d->bd_bif == 0)				error = EINVAL;			else {				ifp = d->bd_bif->bif_ifp;				error = (*ifp->if_ioctl)(ifp, cmd, addr);			}			break;		}	/*	 * Get buffer len [for read()].	 */	case BIOCGBLEN:		*(u_int *)addr = d->bd_bufsize;		break;	/*	 * Set buffer length.	 */	case BIOCSBLEN:#if BSD < 199103		error = EINVAL;#else		if (d->bd_bif != 0)			error = EINVAL;		else {			register u_int size = *(u_int *)addr;			if (size > BPF_MAXBUFSIZE)				*(u_int *)addr = size = BPF_MAXBUFSIZE;			else if (size < BPF_MINBUFSIZE)				*(u_int *)addr = size = BPF_MINBUFSIZE;			d->bd_bufsize = size;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -