diff options
author | sam <sam@FreeBSD.org> | 2003-01-20 19:08:46 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2003-01-20 19:08:46 +0000 |
commit | e74e7998d85e20fd5058a68774726109a7e871c3 (patch) | |
tree | 51dc91b693b58616b22b6d7ee57801e66b2f868c /sys | |
parent | 63b49e34b0350fa2f80e80e3a4c3b6adb875d9bb (diff) | |
download | FreeBSD-src-e74e7998d85e20fd5058a68774726109a7e871c3.zip FreeBSD-src-e74e7998d85e20fd5058a68774726109a7e871c3.tar.gz |
o add BIOCGDLTLIST and BIOCSDLT ioctls to get the data link type list
and set the link type for use by libpcap and tcpdump
o move mtx unlock in bpfdetach up; it doesn't need to be held so long
o change printf in bpf_detach to distinguish it from the same one in bpfsetdlt
Note there are locking issues here related to ioctl processing; they
have not been addressed here.
Submitted by: Guy Harris <guy@alum.mit.edu>
Obtained from: NetBSD (w/ locking modifications)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/bpf.c | 105 | ||||
-rw-r--r-- | sys/net/bpf.h | 10 |
2 files changed, 111 insertions, 4 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c index 4fe5207..df210e2 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -109,6 +109,8 @@ static void catchpacket(struct bpf_d *, u_char *, u_int, u_int, void (*)(const void *, void *, size_t)); static void reset_d(struct bpf_d *); static int bpf_setf(struct bpf_d *, struct bpf_program *); +static int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *); +static int bpf_setdlt(struct bpf_d *, u_int); static d_open_t bpfopen; static d_close_t bpfclose; @@ -286,7 +288,8 @@ bpf_detachd(d) * the driver into promiscuous mode, but can't * take it out. */ - if_printf(bp->bif_ifp, "ifpromisc failed %d\n", error); + if_printf(bp->bif_ifp, + "bpf_detach: ifpromisc failed (%d)\n", error); } } /* Remove d from the interface's descriptor list. */ @@ -736,7 +739,7 @@ bpfioctl(dev, cmd, addr, flags, td) break; /* - * Get device parameters. + * Get current data link type. */ case BIOCGDLT: if (d->bd_bif == 0) @@ -745,6 +748,26 @@ bpfioctl(dev, cmd, addr, flags, td) *(u_int *)addr = d->bd_bif->bif_dlt; break; + /* + * Get a list of supported data link types. + */ + case BIOCGDLTLIST: + if (d->bd_bif == 0) + error = EINVAL; + else + error = bpf_getdltlist(d, (struct bpf_dltlist *)addr); + break; + + /* + * Set data link type. + */ + case BIOCSDLT: + if (d->bd_bif == 0) + error = EINVAL; + else + error = bpf_setdlt(d, *(u_int *)addr); + break; + /* * Get interface name. */ @@ -1331,10 +1354,10 @@ bpfdetach(ifp) struct bpf_if *bp, *bp_prev; struct bpf_d *d; - mtx_lock(&bpf_mtx); - /* Locate BPF interface information */ bp_prev = NULL; + + mtx_lock(&bpf_mtx); for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) { if (ifp == bp->bif_ifp) break; @@ -1354,6 +1377,7 @@ bpfdetach(ifp) } else { bpf_iflist = bp->bif_next; } + mtx_unlock(&bpf_mtx); while ((d = bp->bif_dlist) != NULL) { bpf_detachd(d); @@ -1364,8 +1388,81 @@ bpfdetach(ifp) mtx_destroy(&bp->bif_mtx); free(bp, M_BPF); +} + +/* + * Get a list of available data link type of the interface. + */ +static int +bpf_getdltlist(d, bfl) + struct bpf_d *d; + struct bpf_dltlist *bfl; +{ + int n, error; + struct ifnet *ifp; + struct bpf_if *bp; + + ifp = d->bd_bif->bif_ifp; + n = 0; + error = 0; + mtx_lock(&bpf_mtx); + for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) { + if (bp->bif_ifp != ifp) + continue; + if (bfl->bfl_list != NULL) { + if (n >= bfl->bfl_len) { + mtx_unlock(&bpf_mtx); + return (ENOMEM); + } + error = copyout(&bp->bif_dlt, + bfl->bfl_list + n, sizeof(u_int)); + } + n++; + } + mtx_unlock(&bpf_mtx); + bfl->bfl_len = n; + return (error); +} + +/* + * Set the data link type of a BPF instance. + */ +static int +bpf_setdlt(d, dlt) + struct bpf_d *d; + u_int dlt; +{ + int error, opromisc; + struct ifnet *ifp; + struct bpf_if *bp; + if (d->bd_bif->bif_dlt == dlt) + return (0); + ifp = d->bd_bif->bif_ifp; + mtx_lock(&bpf_mtx); + for (bp = bpf_iflist; bp != NULL; bp = bp->bif_next) { + if (bp->bif_ifp == ifp && bp->bif_dlt == dlt) + break; + } mtx_unlock(&bpf_mtx); + if (bp != NULL) { + BPFD_LOCK(d); + opromisc = d->bd_promisc; + bpf_detachd(d); + bpf_attachd(d, bp); + reset_d(d); + BPFD_UNLOCK(d); + if (opromisc) { + error = ifpromisc(bp->bif_ifp, 1); + if (error) + if_printf(bp->bif_ifp, + "bpf_setdlt: ifpromisc failed (%d)\n", + error); + else + d->bd_promisc = 1; + } + } + return (bp == NULL ? EINVAL : 0); } static void bpf_drvinit(void *unused); diff --git a/sys/net/bpf.h b/sys/net/bpf.h index 5e931ce..6d3e800 100644 --- a/sys/net/bpf.h +++ b/sys/net/bpf.h @@ -115,6 +115,8 @@ struct bpf_version { #define BIOCSHDRCMPLT _IOW('B',117, u_int) #define BIOCGSEESENT _IOR('B',118, u_int) #define BIOCSSEESENT _IOW('B',119, u_int) +#define BIOCSDLT _IOW('B',120, u_int) +#define BIOCGDLTLIST _IOWR('B',121, struct bpf_dltlist) /* * Structure prepended to each packet. @@ -339,6 +341,14 @@ struct bpf_insn { #define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } #define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } +/* + * Structure to retrieve available DLTs for the interface. + */ +struct bpf_dltlist { + u_int bfl_len; /* number of bfd_list array */ + u_int *bfl_list; /* array of DLTs */ +}; + #ifdef _KERNEL struct bpf_if; int bpf_validate(const struct bpf_insn *, int); |