I restored the functionality according to the manpage.

That means that read() on bpf is blocking again. If a
timeout is set read() will block until the timeout is
over.

Maybe asynchronous is also broken, i will look into that later.

Index: sys/net/bpf.c
===================================================================
RCS file: /cvs/src/sys/net/bpf.c,v
retrieving revision 1.103
diff -u -p -r1.103 bpf.c
--- sys/net/bpf.c       12 Jul 2014 18:44:22 -0000      1.103
+++ sys/net/bpf.c       4 Jan 2015 14:22:48 -0000
@@ -433,12 +433,17 @@ bpfread(dev_t dev, struct uio *uio, int 
                if (d->bd_rtout == -1) {
                        /* User requested non-blocking I/O */
                        error = EWOULDBLOCK;
+               } else if (d->bd_rtout == 0) {
+                       /* No timeout? let's wait half a second for an
+                        * interrupt */
+                       error = tsleep((caddr_t)d, PRINET|PCATCH, "bpf",
+                                   hz / 2);
+                       if (error == EWOULDBLOCK)
+                               error = 0;
                } else {
-                       if ((d->bd_rdStart + d->bd_rtout) < ticks) {
-                               error = tsleep((caddr_t)d, PRINET|PCATCH, "bpf",
+                       /* User requested timeout */
+                       error = tsleep((caddr_t)d, PRINET|PCATCH, "bpf",
                                    d->bd_rtout);
-                       } else
-                               error = EWOULDBLOCK;
                }
                if (error == EINTR || error == ERESTART) {
                        D_PUT(d);


To test my patch i wrote a small tool. This tool filters 'finger'
packages.

/* BEGINNING */
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <err.h>

#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/bpf.h>
#include <net/ethertypes.h>
#include <netinet/in.h>
#include <net/if.h>

void usage();
void handler(int);

u_int BUFFFER_SIZE = 32786;
struct bpf_program bpf_machine  = {
        13,
        (struct bpf_insn []){
                BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
                BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_IP, 0, 10),
                BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 23),
                BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_TCP, 0, 8),
                BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20),
                BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x1fff, 6, 0),
                BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 14),
                BPF_STMT(BPF_LD+BPF_H+BPF_IND, 14),
                BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 79, 2, 0),
                BPF_STMT(BPF_LD+BPF_H+BPF_IND, 16),
                BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 79, 0, 1),
                BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
                BPF_STMT(BPF_RET+BPF_K, 0),
        },
};
struct timeval timeout = {
        (time_t)0,
        (suseconds_t)0,
};
struct ifreq interface;
struct sigaction sigact;
int fd, out, pid;
const char *error;
int ch, nflag, tflag, bflag, iflag, dflag, qflag, pflag, aflag;
/* nflag = interface name */
/* tflag = timeout in seconds */
/* blfag = non-blocking */
/* iflag = immediate mode */
/* dflag = bpf devic, absolut path */
/* qflag = buffersize */
/* pflag = promiscius mode */
/* aflag = async mode */

int
main(int argc, char **argv)
{
        while ((ch = getopt(argc, argv, "n:t:bid:q:pa")) != -1) {
                switch (ch) {
                case 'n':
                        nflag = 1;
                        strlcpy(interface.ifr_name, optarg,
                            sizeof(interface.ifr_name));
                        break;
                case 't':
                        tflag = 1;
                        timeout.tv_sec = strtonum(optarg, 1, 600, &error);
                        if (error)
                                errx(1, "max timeout %s: %s", error, optarg);
                        break;
                case 'b':
                        bflag = 1;
                        break;
                case 'i':
                        iflag = 1;
                        break;
                case 'd':
                        dflag = 1;
                        if ((fd = open(optarg, O_RDONLY)) < 0)
                                errx(1, "open: %s", strerror(errno));
                        break;
                case 'q':
                        qflag = 1;
                        if (((BUFFFER_SIZE = strtonum(optarg, 1024, 4194304,
                            &error)) % 1024) != 0)
                                errx(1, "buffer has to be '% 1024 == 0'");
                        break;
                case 'p':
                        pflag = 1;
                        break;
                case 'a':
                        aflag = 1;
                        sigact.sa_handler = handler;
                        pid = getpid();
                        if (sigaction(SIGIO, &sigact, NULL) < 0)
                                errx(1, "sigaction: %s", strerror(errno));
                        break;
                default:
                        usage();
                        /* NOTREACHED */
                }
        }
        argc -= optind;
        argv += optind;

        u_char buffer[BUFFFER_SIZE];
        
        if (dflag != 1)
                errx(1, "no bpfdevice");
        
        if (ioctl(fd, BIOCSBLEN, &BUFFFER_SIZE) < 0)
                errx(1, "BIOCSBLEN: %s", strerror(errno));

        if (nflag != 1)
                errx(1, "no ifname");
        if(ioctl(fd, BIOCSETIF, &interface) < 0)
                errx(1, "BIOCSETIF: %s", strerror(errno));
        printf("Interface: %s\n", interface.ifr_name);

        if (pflag == 1)
                if (ioctl(fd, BIOCPROMISC) < 0)
                        errx(1, "BIOCPROMISC: %s", strerror(errno));

        if (ioctl(fd, FIONBIO, &bflag) < 0)
                errx(1, "FIONBIO: %s", strerror(errno));

        if (ioctl(fd, BIOCIMMEDIATE, &iflag) < 0)
                errx(1, "BIOCIMMEDIATE: %s", strerror(errno));

        if (aflag == 1) {
                if (ioctl(fd, FIOSETOWN, &pid) < 0)
                        errx(1, "FIOSETOWN: %s", strerror(errno));
                if (ioctl(fd, FIOASYNC, &aflag) < 0)
                        errx(1, "FIOASYNC: %s", strerror(errno));
        }

        if (tflag == 1) {
                if (ioctl(fd, BIOCSRTIMEOUT, &timeout) < 0)
                        errx(1, "BIOCSRTIMEOUT: %s", strerror(errno));
                printf("Timeout: %lli\n", timeout.tv_sec);
        }

        if (ioctl(fd, BIOCSETF, &bpf_machine) < 0)
                errx(1, "BIOCSETF: %s", strerror(errno));

        out = read(fd, buffer, sizeof(buffer));
        if (out < 0)
                errx(1, "read: %s", strerror(errno));

        printf("read?: %i\n", out);

        return 0;
}

void
usage(void)
{
        printf("usage: bpf_test [-bipa] [-t timeout] [-q buffersize] -n "
               "ifname -d bpfdevice\n");
        exit(0);
}

void
handler(int signal)
{
        printf("Match!\n");
}
/* END */

BR

Simon

Reply via email to