BPF BIOCSETF

Kip Macy kip.macy at gmail.com
Sun Nov 18 19:51:58 PST 2007


On Nov 18, 2007 7:18 PM, Matthew Luckie <mluckie at cs.waikato.ac.nz> wrote:
> 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.
>
> Patch below is against RELENG_6.  I'll send a PR tomorrow against HEAD
> if there aren't any comments or complaints; the main difference will
> be the extra cruft to make bpf_jitter work.
>
> Thoughts?
>
> Matthew
>
> --- bpf.c.orig  Mon Nov 19 14:23:52 2007
> +++ bpf.c       Mon Nov 19 15:55:05 2007
> @@ -103,7 +103,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 *);
> @@ -755,8 +756,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;
>
>         /*
> @@ -976,26 +981,17 @@
>   * 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;
>
> -       if (cmd == BIOCSETWF) {
> -               old = d->bd_wfilter;
> -               wfilter = 1;
> -       } else {
> -               wfilter = 0;
> -               old = d->bd_rfilter;
> -       }
>         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;
>                 reset_d(d);
>                 BPFD_UNLOCK(d);
>                 if (old != NULL)
> @@ -1011,10 +1007,8 @@
>         if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 &&
>             bpf_validate(fcode, (int)flen)) {
>                 BPFD_LOCK(d);
> -               if (wfilter)
> -                       d->bd_wfilter = fcode;
> -               else
> -                       d->bd_rfilter = fcode;
> +               old = d->bd_rfilter;
> +               d->bd_rfilter = fcode;
>                 reset_d(d);
>                 BPFD_UNLOCK(d);
>                 if (old != NULL)
> @@ -1024,6 +1018,50 @@
>         }
>         free((caddr_t)fcode, M_BPF);
>         return (EINVAL);
> +}
> +
> +/*
> + * Set d's packet filter program to fp.  If this file already has a filter,
> + * replace it but keep any existing buffered packets.
> + */
> +static int
> +bpf_setfnr(struct bpf_d *d, struct bpf_program *fp, u_long cmd)
> +{
> +       struct bpf_insn *fcode, *old;
> +       u_int flen, size;
> +
> +       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);
> +               }
> +       } else {
> +               if (fp->bf_len != 0)
> +                       return (EINVAL);
> +               fcode = NULL;
> +       }
> +
> +       BPFD_LOCK(d);
> +       if (cmd == BIOCSETFNR) {
> +               old = d->bd_rfilter;
> +               d->bd_rfilter = fcode;
> +       } else {
> +               old = d->bd_wfilter;
> +               d->bd_wfilter = fcode;
> +       }
> +       BPFD_UNLOCK(d);
> +
> +       if(old != NULL)
> +               free((caddr_t)old, M_BPF);
> +
> +       return (0);
>  }
>
>  /*
> --- bpf.h.orig  Mon Nov 19 14:24:11 2007
> +++ bpf.h       Mon Nov 19 14:25:16 2007
> @@ -115,6 +115,7 @@
>  #define        BIOCGDLTLIST    _IOWR('B',121, struct bpf_dltlist)
>  #define        BIOCLOCK        _IO('B', 122)
>  #define        BIOCSETWF       _IOW('B',123, struct bpf_program)
> +#define BIOCSETFNR     _IOW('B',124, struct bpf_program)
>
>  /*
>   * Structure prepended to each packet.

Sounds reasonable. Christian has been active in maintaining BPF
recently so he is really the one you need to follow up with.

 -Kip


More information about the freebsd-net mailing list