Fix bpf so that select will return for a timeout (from FreeBSD.)
Fix the behaviour of BIOCIMMEDIATE (fix from LBL BPF code via FreeBSD.) In bpf_mtap(), optimise the calling of bpf_filter() and catchpacket() based on whether or not the entire packet is in one mbuf (based on similar change FreeBSD but fixes BIOC*SEESENT issue with that.) Copy the implementation of BIOCSSEESENT, BIOCGSEESENT by FreeBSD. Review Assistance: Guy Harris PRs: kern/8674, kern/12170
This commit is contained in:
parent
0488cca3a2
commit
eee3190c06
115
sys/net/bpf.c
115
sys/net/bpf.c
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: bpf.c,v 1.90 2004/03/24 15:34:54 atatat Exp $ */
|
||||
/* $NetBSD: bpf.c,v 1.91 2004/04/10 23:31:51 darrenr Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990, 1991, 1993
|
||||
|
@ -39,7 +39,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.90 2004/03/24 15:34:54 atatat Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.91 2004/04/10 23:31:51 darrenr Exp $");
|
||||
|
||||
#include "bpfilter.h"
|
||||
|
||||
|
@ -114,6 +114,7 @@ static int bpf_movein __P((struct uio *, int, int,
|
|||
static void bpf_attachd __P((struct bpf_d *, struct bpf_if *));
|
||||
static void bpf_detachd __P((struct bpf_d *));
|
||||
static int bpf_setif __P((struct bpf_d *, struct ifreq *));
|
||||
static void bpf_timed_out __P((void *));
|
||||
static __inline void
|
||||
bpf_wakeup __P((struct bpf_d *));
|
||||
static void catchpacket __P((struct bpf_d *, u_char *, u_int, u_int,
|
||||
|
@ -380,6 +381,8 @@ bpfopen(dev, flag, mode, p)
|
|||
/* Mark "free" and do most initialization. */
|
||||
memset((char *)d, 0, sizeof(*d));
|
||||
d->bd_bufsize = bpf_bufsize;
|
||||
d->bd_seesent = 1;
|
||||
callout_init(&d->bd_callout);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -400,6 +403,9 @@ bpfclose(dev, flag, mode, p)
|
|||
int s;
|
||||
|
||||
s = splnet();
|
||||
if (d->bd_state == BPF_WAITING)
|
||||
callout_stop(&d->bd_callout);
|
||||
d->bd_state = BPF_IDLE;
|
||||
if (d->bd_bif)
|
||||
bpf_detachd(d);
|
||||
splx(s);
|
||||
|
@ -429,6 +435,7 @@ bpfread(dev, uio, ioflag)
|
|||
int ioflag;
|
||||
{
|
||||
struct bpf_d *d = &bpf_dtab[minor(dev)];
|
||||
int timed_out;
|
||||
int error;
|
||||
int s;
|
||||
|
||||
|
@ -440,17 +447,17 @@ bpfread(dev, uio, ioflag)
|
|||
return (EINVAL);
|
||||
|
||||
s = splnet();
|
||||
if (d->bd_state == BPF_WAITING)
|
||||
callout_stop(&d->bd_callout);
|
||||
timed_out = (d->bd_state == BPF_TIMED_OUT);
|
||||
d->bd_state = BPF_IDLE;
|
||||
/*
|
||||
* 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) {
|
||||
if (d->bd_slen == 0) {
|
||||
splx(s);
|
||||
return (EWOULDBLOCK);
|
||||
}
|
||||
if ((d->bd_immediate || timed_out) && d->bd_slen != 0) {
|
||||
/*
|
||||
* A packet(s) either arrived since the previous
|
||||
* read or arrived while we were asleep.
|
||||
|
@ -463,11 +470,8 @@ bpfread(dev, uio, ioflag)
|
|||
error = tsleep((caddr_t)d, PRINET|PCATCH, "bpf",
|
||||
d->bd_rtout);
|
||||
else {
|
||||
if (d->bd_rtout == -1) {
|
||||
/* User requested non-blocking I/O */
|
||||
error = EWOULDBLOCK;
|
||||
} else
|
||||
error = 0;
|
||||
/* User requested non-blocking I/O */
|
||||
error = EWOULDBLOCK;
|
||||
}
|
||||
if (error == EINTR || error == ERESTART) {
|
||||
splx(s);
|
||||
|
@ -535,6 +539,24 @@ bpf_wakeup(d)
|
|||
d->bd_sel.sel_pid = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
bpf_timed_out(arg)
|
||||
void *arg;
|
||||
{
|
||||
struct bpf_d *d = (struct bpf_d *)arg;
|
||||
int s;
|
||||
|
||||
s = splnet();
|
||||
if (d->bd_state == BPF_WAITING) {
|
||||
d->bd_state = BPF_TIMED_OUT;
|
||||
if (d->bd_slen != 0)
|
||||
bpf_wakeup(d);
|
||||
}
|
||||
splx(s);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
bpfwrite(dev, uio, ioflag)
|
||||
dev_t dev;
|
||||
|
@ -631,6 +653,12 @@ bpfioctl(dev, cmd, addr, flag, p)
|
|||
struct bpf_insn **p;
|
||||
#endif
|
||||
|
||||
s = splnet();
|
||||
if (d->bd_state == BPF_WAITING)
|
||||
callout_stop(&d->bd_callout);
|
||||
d->bd_state = BPF_IDLE;
|
||||
splx(s);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
default:
|
||||
|
@ -853,6 +881,20 @@ bpfioctl(dev, cmd, addr, flag, p)
|
|||
d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Get "see sent packets" flag
|
||||
*/
|
||||
case BIOCGSEESENT:
|
||||
*(u_int *)addr = d->bd_seesent;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Set "see sent" packets flag
|
||||
*/
|
||||
case BIOCSSEESENT:
|
||||
d->bd_seesent = *(u_int *)addr;
|
||||
break;
|
||||
|
||||
case FIONBIO: /* Non-blocking I/O */
|
||||
if (*(int *)addr)
|
||||
d->bd_rtout = -1;
|
||||
|
@ -1040,10 +1082,19 @@ bpfpoll(dev, events, p)
|
|||
/*
|
||||
* An imitation of the FIONREAD ioctl code.
|
||||
*/
|
||||
if (d->bd_hlen != 0 || (d->bd_immediate && d->bd_slen != 0))
|
||||
if (d->bd_hlen != 0 ||
|
||||
((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) &&
|
||||
d->bd_slen != 0))
|
||||
revents |= events & (POLLIN | POLLRDNORM);
|
||||
else
|
||||
else {
|
||||
selrecord(p, &d->bd_sel);
|
||||
/* Start the read timeout if necessary */
|
||||
if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) {
|
||||
callout_reset(&d->bd_callout, d->bd_rtout,
|
||||
bpf_timed_out, d);
|
||||
d->bd_state = BPF_WAITING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
splx(s);
|
||||
|
@ -1168,20 +1219,34 @@ bpf_mtap(arg, m)
|
|||
caddr_t arg;
|
||||
struct mbuf *m;
|
||||
{
|
||||
void *(*cpfn) __P((void *, const void *, size_t));
|
||||
struct bpf_if *bp = (struct bpf_if *)arg;
|
||||
struct bpf_d *d;
|
||||
u_int pktlen, slen;
|
||||
u_int pktlen, slen, buflen;
|
||||
struct mbuf *m0;
|
||||
void *marg;
|
||||
|
||||
pktlen = 0;
|
||||
for (m0 = m; m0 != 0; m0 = m0->m_next)
|
||||
pktlen += m0->m_len;
|
||||
|
||||
if (pktlen == m->m_len) {
|
||||
cpfn = memcpy;
|
||||
marg = mtod(m, void *);
|
||||
buflen = pktlen;
|
||||
} else {
|
||||
cpfn = bpf_mcpy;
|
||||
marg = m;
|
||||
buflen = 0;
|
||||
}
|
||||
|
||||
for (d = bp->bif_dlist; d != 0; d = d->bd_next) {
|
||||
if (!d->bd_seesent && (m->m_pkthdr.rcvif == NULL))
|
||||
continue;
|
||||
++d->bd_rcount;
|
||||
slen = bpf_filter(d->bd_filter, (u_char *)m, pktlen, 0);
|
||||
slen = bpf_filter(d->bd_filter, marg, pktlen, buflen);
|
||||
if (slen != 0)
|
||||
catchpacket(d, (u_char *)m, pktlen, slen, bpf_mcpy);
|
||||
catchpacket(d, marg, pktlen, slen, cpfn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1234,7 +1299,13 @@ catchpacket(d, pkt, pktlen, snaplen, cpfn)
|
|||
ROTATE_BUFFERS(d);
|
||||
bpf_wakeup(d);
|
||||
curlen = 0;
|
||||
}
|
||||
} else if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT)
|
||||
/*
|
||||
* Immediate mode is set, or the read timeout has
|
||||
* already expired during a select call. A packet
|
||||
* arrived, so the reader should be woken up.
|
||||
*/
|
||||
bpf_wakeup(d);
|
||||
|
||||
/*
|
||||
* Append the bpf header.
|
||||
|
@ -1248,14 +1319,6 @@ catchpacket(d, pkt, pktlen, snaplen, cpfn)
|
|||
*/
|
||||
(*cpfn)((u_char *)hp + hdrlen, pkt, (hp->bh_caplen = totlen - hdrlen));
|
||||
d->bd_slen = curlen + totlen;
|
||||
|
||||
if (d->bd_immediate) {
|
||||
/*
|
||||
* Immediate mode is set. A packet arrived so any
|
||||
* reads should be woken up.
|
||||
*/
|
||||
bpf_wakeup(d);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: bpf.h,v 1.33 2004/01/22 00:32:41 jonathan Exp $ */
|
||||
/* $NetBSD: bpf.h,v 1.34 2004/04/10 23:31:52 darrenr Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990, 1991, 1993
|
||||
|
@ -102,12 +102,12 @@ struct bpf_version {
|
|||
* header files. If your using gcc, we assume that you
|
||||
* have run fixincludes so the latter set should work.
|
||||
*/
|
||||
#define BIOCGBLEN _IOR('B',102, u_int)
|
||||
#define BIOCSBLEN _IOWR('B',102, u_int)
|
||||
#define BIOCSETF _IOW('B',103, struct bpf_program)
|
||||
#define BIOCFLUSH _IO('B',104)
|
||||
#define BIOCGBLEN _IOR('B',102, u_int)
|
||||
#define BIOCSBLEN _IOWR('B',102, u_int)
|
||||
#define BIOCSETF _IOW('B',103, struct bpf_program)
|
||||
#define BIOCFLUSH _IO('B',104)
|
||||
#define BIOCPROMISC _IO('B',105)
|
||||
#define BIOCGDLT _IOR('B',106, u_int)
|
||||
#define BIOCGDLT _IOR('B',106, u_int)
|
||||
#define BIOCGETIF _IOR('B',107, struct ifreq)
|
||||
#define BIOCSETIF _IOW('B',108, struct ifreq)
|
||||
#define BIOCSRTIMEOUT _IOW('B',109, struct timeval)
|
||||
|
@ -117,10 +117,12 @@ struct bpf_version {
|
|||
#define BIOCVERSION _IOR('B',113, struct bpf_version)
|
||||
#define BIOCSTCPF _IOW('B',114, struct bpf_program)
|
||||
#define BIOCSUDPF _IOW('B',115, struct bpf_program)
|
||||
#define BIOCGHDRCMPLT _IOR('B',116, u_int)
|
||||
#define BIOCSHDRCMPLT _IOW('B',117, u_int)
|
||||
#define BIOCSDLT _IOW('B',118, u_int)
|
||||
#define BIOCGDLTLIST _IOWR('B',119, struct bpf_dltlist)
|
||||
#define BIOCGHDRCMPLT _IOR('B',116, u_int)
|
||||
#define BIOCSHDRCMPLT _IOW('B',117, u_int)
|
||||
#define BIOCSDLT _IOW('B',118, u_int)
|
||||
#define BIOCGDLTLIST _IOWR('B',119, struct bpf_dltlist)
|
||||
#define BIOCGSEESENT _IOR('B',120, u_int)
|
||||
#define BIOCSSEESENT _IOW('B',121, u_int)
|
||||
|
||||
/*
|
||||
* Structure prepended to each packet.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: bpfdesc.h,v 1.16 2003/08/07 16:32:48 agc Exp $ */
|
||||
/* $NetBSD: bpfdesc.h,v 1.17 2004/04/10 23:31:52 darrenr Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990, 1991, 1993
|
||||
|
@ -41,6 +41,7 @@
|
|||
#ifndef _NET_BPFDESC_H_
|
||||
#define _NET_BPFDESC_H_
|
||||
|
||||
#include <sys/callout.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
/*
|
||||
|
@ -75,6 +76,7 @@ struct bpf_d {
|
|||
u_char bd_state; /* idle, waiting, or timed out */
|
||||
u_char bd_immediate; /* true to return on packet arrival */
|
||||
int bd_hdrcmplt; /* false to fill in src lladdr */
|
||||
int bd_seesent; /* true if bpf should see sent packets */
|
||||
int bd_async; /* non-zero if packet reception should generate signal */
|
||||
pid_t bd_pgid; /* process or group id for signal */
|
||||
#if BSD < 199103
|
||||
|
@ -85,8 +87,15 @@ struct bpf_d {
|
|||
u_char bd_pad; /* explicit alignment */
|
||||
struct selinfo bd_sel; /* bsd select info */
|
||||
#endif
|
||||
struct callout bd_callout; /* for BPF timeouts with select */
|
||||
};
|
||||
|
||||
|
||||
/* Values for bd_state */
|
||||
#define BPF_IDLE 0 /* no select in progress */
|
||||
#define BPF_WAITING 1 /* waiting for read timeout in select */
|
||||
#define BPF_TIMED_OUT 2 /* read timeout has expired in select */
|
||||
|
||||
/*
|
||||
* Descriptor associated with each attached hardware interface.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue