From owner-freebsd-bugs@FreeBSD.ORG Fri Dec 7 21:10:02 2007 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8381516A417 for ; Fri, 7 Dec 2007 21:10:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 6020513C442 for ; Fri, 7 Dec 2007 21:10:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.14.2/8.14.2) with ESMTP id lB7LA2lI017914 for ; Fri, 7 Dec 2007 21:10:02 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.2/8.14.1/Submit) id lB7LA2pW017913; Fri, 7 Dec 2007 21:10:02 GMT (envelope-from gnats) Resent-Date: Fri, 7 Dec 2007 21:10:02 GMT Resent-Message-Id: <200712072110.lB7LA2pW017913@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Matthew Luckie Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 682FE16A46C for ; Fri, 7 Dec 2007 21:07:41 +0000 (UTC) (envelope-from mluckie@cs.waikato.ac.nz) Received: from zombie.scms.waikato.ac.nz (mail.scms.waikato.ac.nz [130.217.241.36]) by mx1.freebsd.org (Postfix) with ESMTP id F273513C467 for ; Fri, 7 Dec 2007 21:07:40 +0000 (UTC) (envelope-from mluckie@cs.waikato.ac.nz) Received: from sorcerer.cs.waikato.ac.nz ([130.217.250.39]) by zombie.scms.waikato.ac.nz with esmtps (TLSv1:AES256-SHA:256) (Exim 4.52) id 1J0jmO-0001fx-C1 for FreeBSD-gnats-submit@freebsd.org; Sat, 08 Dec 2007 09:26:36 +1300 Received: from mluckie by sorcerer.cs.waikato.ac.nz with local (Exim 4.68 (FreeBSD)) (envelope-from ) id 1J0jmN-000GpX-OS for FreeBSD-gnats-submit@freebsd.org; Sat, 08 Dec 2007 09:26:35 +1300 Message-Id: Date: Sat, 08 Dec 2007 09:26:35 +1300 From: Matthew Luckie Sender: Matthew Luckie To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: Subject: kern/118486: [patch][bpf] change BPF filters without discarding buffered packets X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Matthew Luckie List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 07 Dec 2007 21:10:02 -0000 >Number: 118486 >Category: kern >Synopsis: [patch][bpf] change BPF filters without discarding buffered packets >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Fri Dec 07 21:10:01 UTC 2007 >Closed-Date: >Last-Modified: >Originator: Matthew Luckie >Release: FreeBSD 6.2-STABLE i386 >Organization: >Environment: System: FreeBSD sorcerer.cs.waikato.ac.nz 6.2-STABLE FreeBSD 6.2-STABLE #0: Mon May 14 13:25:05 NZST 2007 root@sorcerer.cs.waikato.ac.nz:/usr/obj/usr/src/sys/SMP i386 >Description: BIOCSETF and BIOCSETWF call reset_d which discards any packets currently in the hold buffer and resets the packet rx count. The patch below adds BIOCSETFNR, an ioctl that swaps the BPF filter without resetting the hold buffer and without resetting the packet rx counts, which is handy when the application wants to adjust its filter program but without discarding whatever the system might have buffered. I've also changed BIOCSETWF to map to the new function. I don't see the rationale in having BIOCSETWF mucking with the receive stats and hold buffer. >How-To-Repeat: >Fix: Patch against -HEAD below. --- bpf-setfnr.patch begins here --- --- sys/net/bpf.c.orig Mon Nov 19 16:09:09 2007 +++ sys/net/bpf.c Sat Nov 24 12:14:23 2007 @@ -112,7 +112,8 @@ u_int, void (*)(const void *, void *, size_t), struct timeval *); static void reset_d(struct bpf_d *); -static int bpf_setf(struct bpf_d *, struct bpf_program *, u_long cmd); +static int bpf_setf(struct bpf_d *, struct bpf_program *); +static int bpf_setfnr(struct bpf_d *, struct bpf_program *, u_long); static int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *); static int bpf_setdlt(struct bpf_d *, u_int); static void filt_bpfdetach(struct knote *); @@ -681,7 +682,6 @@ static void reset_d(struct bpf_d *d) { - mtx_assert(&d->bd_mtx, MA_OWNED); if (d->bd_hbuf) { /* Free the hold buffer. */ @@ -699,8 +699,9 @@ * 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. - * BIOCSETWF Set ethernet write filter. + * BIOCSETF Set read filter. + * BIOCSETFNR Set read filter without resetting descriptor. + * BIOCSETWF Set write filter. * BIOCFLUSH Flush read packet buffer. * BIOCPROMISC Put interface into promiscuous mode. * BIOCGDLT Get link layer type. @@ -823,8 +824,12 @@ * Set link layer read filter. */ case BIOCSETF: + error = bpf_setf(d, (struct bpf_program *)addr); + break; + + case BIOCSETFNR: case BIOCSETWF: - error = bpf_setf(d, (struct bpf_program *)addr, cmd); + error = bpf_setfnr(d, (struct bpf_program *)addr, cmd); break; /* @@ -1060,39 +1065,24 @@ * free it and replace it. Returns EINVAL for bogus requests. */ static int -bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd) +bpf_setf(struct bpf_d *d, struct bpf_program *fp) { struct bpf_insn *fcode, *old; - u_int wfilter, flen, size; + u_int flen, size; #ifdef BPF_JITTER - bpf_jit_filter *ofunc; + bpf_jit_filter *ofunc, *nfunc; #endif - if (cmd == BIOCSETWF) { - old = d->bd_wfilter; - wfilter = 1; -#ifdef BPF_JITTER - ofunc = NULL; -#endif - } else { - wfilter = 0; - old = d->bd_rfilter; -#ifdef BPF_JITTER - ofunc = d->bd_bfilter; -#endif - } if (fp->bf_insns == NULL) { if (fp->bf_len != 0) return (EINVAL); BPFD_LOCK(d); - if (wfilter) - d->bd_wfilter = NULL; - else { - d->bd_rfilter = NULL; + old = d->bd_rfilter; + d->bd_rfilter = NULL; #ifdef BPF_JITTER - d->bd_bfilter = NULL; + ofunc = d->bd_bfilter; + d->bd_bfilter = NULL; #endif - } reset_d(d); BPFD_UNLOCK(d); if (old != NULL) @@ -1111,15 +1101,16 @@ fcode = (struct bpf_insn *)malloc(size, M_BPF, M_WAITOK); if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 && bpf_validate(fcode, (int)flen)) { +#ifdef BPF_JITTER + nfunc = bpf_jitter(fcode, flen); +#endif BPFD_LOCK(d); - if (wfilter) - d->bd_wfilter = fcode; - else { - d->bd_rfilter = fcode; + old = d->bd_rfilter; + d->bd_rfilter = fcode; #ifdef BPF_JITTER - d->bd_bfilter = bpf_jitter(fcode, flen); + ofunc = d->bd_bfilter; + d->bd_bfilter = nfunc; #endif - } reset_d(d); BPFD_UNLOCK(d); if (old != NULL) @@ -1128,11 +1119,70 @@ if (ofunc != NULL) bpf_destroy_jit_filter(ofunc); #endif - return (0); } free((caddr_t)fcode, M_BPF); return (EINVAL); +} + +static int +bpf_setfnr(struct bpf_d *d, struct bpf_program *fp, u_long cmd) +{ + struct bpf_insn *fcode, *old; + u_int flen, size; +#ifdef BPF_JITTER + bpf_jit_filter *ofunc, *nfunc; +#endif + + if (fp->bf_insns != NULL) { + flen = fp->bf_len; + if (flen > bpf_maxinsns) + return (EINVAL); + + size = flen * sizeof(*fp->bf_insns); + fcode = (struct bpf_insn *)malloc(size, M_BPF, M_WAITOK); + if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) != 0 || + bpf_validate(fcode, (int)flen) == 0) { + free((caddr_t)fcode, M_BPF); + return (EINVAL); + } +#ifdef BPF_JITTER + if (cmd == BIOCSETFNR) + nfunc = bpf_jitter(fcode, flen); + else + nfunc = NULL; +#endif + } else { + if (fp->bf_len != 0) + return (EINVAL); + fcode = NULL; +#ifdef BPF_JITTER + nfunc = NULL; +#endif + } + + BPFD_LOCK(d); + if (cmd == BIOCSETFNR) { + old = d->bd_rfilter; + d->bd_rfilter = fcode; +#ifdef BPF_JITTER + ofunc = d->bd_bfilter; + d->bd_bfilter = nfunc; +#endif + } else { + old = d->bd_wfilter; + d->bd_wfilter = fcode; + } + BPFD_UNLOCK(d); + + if (old != NULL) + free((caddr_t)old, M_BPF); +#ifdef BPF_JITTER + if (ofunc != NULL) + bpf_destroy_jit_filter(ofunc); +#endif + + return (0); } /* --- sys/net/bpf.h.orig Mon Nov 19 16:09:17 2007 +++ sys/net/bpf.h Mon Nov 19 16:09:58 2007 @@ -116,6 +116,7 @@ #define BIOCLOCK _IO('B', 122) #define BIOCSETWF _IOW('B',123, struct bpf_program) #define BIOCFEEDBACK _IOW('B',124, u_int) +#define BIOCSETFNR _IOW('B',125, struct bpf_program) /* Obsolete */ #define BIOCGSEESENT BIOCGDIRECTION --- share/man/man4/bpf.4.orig Fri Nov 23 09:39:01 2007 +++ share/man/man4/bpf.4 Fri Nov 23 09:57:33 2007 @@ -230,6 +230,7 @@ which must respond to messages in real time. The default for a new file is off. .It Dv BIOCSETF +.It Dv BIOCSETFNR .Pq Li "struct bpf_program" Sets the read filter program used by the kernel to discard uninteresting packets. @@ -249,12 +250,21 @@ is given by the .Li bf_len field. -Also, the actions of -.Dv BIOCFLUSH -are performed. See section .Sx "FILTER MACHINE" for an explanation of the filter language. +.Pp +The only difference between +.Dv BIOCSETF +and +.Dv BIOCSETFNR +is +.Dv BIOCSETF +performs the actions of +.Dv BIOCFLUSH +while +.Dv BIOCSETFNR +does not. .It Dv BIOCSETWF .Pq Li "struct bpf_program" Sets the write filter program used by the kernel to control what type of --- bpf-setfnr.patch ends here --- >Release-Note: >Audit-Trail: >Unformatted: