summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/bpf.c59
-rw-r--r--sys/net/bpfdesc.h7
2 files changed, 60 insertions, 6 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index 034ead1..0d93db5 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -100,6 +100,7 @@ static void bpf_mcopy __P((const void *, void *, size_t));
static int bpf_movein __P((struct uio *, int,
struct mbuf **, struct sockaddr *, int *));
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,
@@ -343,6 +344,7 @@ bpfopen(dev, flags, fmt, td)
d->bd_sig = SIGIO;
d->bd_seesent = 1;
mtx_init(&d->bd_mtx, devtoname(dev), MTX_DEF);
+ callout_init(&d->bd_callout, 1);
return (0);
}
@@ -361,6 +363,11 @@ bpfclose(dev, flags, fmt, td)
{
struct bpf_d *d = dev->si_drv1;
+ BPFD_LOCK(d);
+ if (d->bd_state == BPF_WAITING)
+ callout_stop(&d->bd_callout);
+ d->bd_state = BPF_IDLE;
+ BPFD_UNLOCK(d);
funsetown(d->bd_sigio);
mtx_lock(&bpf_mtx);
if (d->bd_bif)
@@ -395,6 +402,7 @@ bpfread(dev, uio, ioflag)
int ioflag;
{
struct bpf_d *d = dev->si_drv1;
+ int timed_out;
int error;
/*
@@ -405,13 +413,17 @@ bpfread(dev, uio, ioflag)
return (EINVAL);
BPFD_LOCK(d);
+ 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 && d->bd_slen != 0) {
+ 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.
@@ -493,6 +505,10 @@ static __inline void
bpf_wakeup(d)
register struct bpf_d *d;
{
+ if (d->bd_state == BPF_WAITING) {
+ callout_stop(&d->bd_callout);
+ d->bd_state = BPF_IDLE;
+ }
wakeup((caddr_t)d);
if (d->bd_async && d->bd_sig && d->bd_sigio)
pgsigio(d->bd_sigio, d->bd_sig, 0);
@@ -502,6 +518,21 @@ bpf_wakeup(d)
d->bd_sel.si_pid = 0;
}
+static void
+bpf_timed_out(arg)
+ void *arg;
+{
+ struct bpf_d *d = (struct bpf_d *)arg;
+
+ BPFD_LOCK(d);
+ if (d->bd_state == BPF_WAITING) {
+ d->bd_state = BPF_TIMED_OUT;
+ if (d->bd_slen != 0)
+ bpf_wakeup(d);
+ }
+ BPFD_UNLOCK(d);
+}
+
static int
bpfwrite(dev, uio, ioflag)
dev_t dev;
@@ -595,6 +626,12 @@ bpfioctl(dev, cmd, addr, flags, td)
struct bpf_d *d = dev->si_drv1;
int error = 0;
+ BPFD_LOCK(d);
+ if (d->bd_state == BPF_WAITING)
+ callout_stop(&d->bd_callout);
+ d->bd_state = BPF_IDLE;
+ BPFD_UNLOCK(d);
+
switch (cmd) {
default:
@@ -987,10 +1024,19 @@ bpfpoll(dev, events, td)
* if (d->b_slen != 0 ||
* (d->bd_hbuf != NULL && d->bd_hlen != 0)
*/
- 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(td, &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;
+ }
+ }
}
BPFD_UNLOCK(d);
return (revents);
@@ -1133,10 +1179,11 @@ catchpacket(d, pkt, pktlen, snaplen, cpfn)
bpf_wakeup(d);
curlen = 0;
}
- else if (d->bd_immediate)
+ else if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT)
/*
- * Immediate mode is set. A packet arrived so any
- * reads should be woken up.
+ * 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);
diff --git a/sys/net/bpfdesc.h b/sys/net/bpfdesc.h
index 7f61d70..7db4193 100644
--- a/sys/net/bpfdesc.h
+++ b/sys/net/bpfdesc.h
@@ -43,6 +43,7 @@
#ifndef _NET_BPFDESC_H_
#define _NET_BPFDESC_H_
+#include <sys/callout.h>
#include <sys/selinfo.h>
/*
@@ -90,8 +91,14 @@ struct bpf_d {
struct selinfo bd_sel; /* bsd select info */
#endif
struct mtx bd_mtx; /* mutex for this descriptor */
+ 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 */
+
#define BPFD_LOCK(bd) mtx_lock(&(bd)->bd_mtx)
#define BPFD_UNLOCK(bd) mtx_unlock(&(bd)->bd_mtx)
OpenPOWER on IntegriCloud