Add three new ioctl(2) commands for bpf(4).

- BIOCGDIRECTION and BIOCSDIRECTION get or set the setting determining
whether incoming, outgoing, or all packets on the interface should be
returned by BPF.  Set to BPF_D_IN to see only incoming packets on the
interface.  Set to BPF_D_INOUT to see packets originating locally and
remotely on the interface.  Set to BPF_D_OUT to see only outgoing
packets on the interface.  This setting is initialized to BPF_D_INOUT
by default.  BIOCGSEESENT and BIOCSSEESENT are obsoleted by these but
kept for backward compatibility.

- BIOCFEEDBACK sets packet feedback mode.  This allows injected packets
to be fed back as input to the interface when output via the interface is
successful.  When BPF_D_INOUT direction is set, injected outgoing packet
is not returned by BPF to avoid duplication.  This flag is initialized to
zero by default.

Note that libpcap has been modified to support BPF_D_OUT direction for
pcap_setdirection(3) and PCAP_D_OUT direction is functional now.

Reviewed by:	rwatson
This commit is contained in:
Jung-uk Kim 2007-02-26 22:24:14 +00:00
parent e7c33e29ed
commit 560a54e10c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=167035
6 changed files with 168 additions and 47 deletions

View File

@ -1093,9 +1093,22 @@ pcap_setfilter_bpf(pcap_t *p, struct bpf_program *fp)
static int
pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d)
{
#ifdef BIOCSSEESENT
#if defined(BIOCSDIRECTION)
u_int direction;
direction = (d == PCAP_D_IN) ? BPF_D_IN :
((d == PCAP_D_OUT) ? BPF_D_OUT : BPF_D_INOUT);
if (ioctl(p->fd, BIOCSDIRECTION, &direction) == -1) {
(void) snprintf(p->errbuf, sizeof(p->errbuf),
"Cannot set direction to %s: %s",
(d == PCAP_D_IN) ? "PCAP_D_IN" :
((d == PCAP_D_OUT) ? "PCAP_D_OUT" : "PCAP_D_INOUT"),
strerror(errno));
return (-1);
}
return (0);
#elif defined(BIOCSSEESENT)
u_int seesent;
#endif
/*
* We don't support PCAP_D_OUT.
@ -1105,7 +1118,7 @@ pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d)
"Setting direction to PCAP_D_OUT is not supported on BPF");
return -1;
}
#ifdef BIOCSSEESENT
seesent = (d == PCAP_D_INOUT);
if (ioctl(p->fd, BIOCSSEESENT, &seesent) == -1) {
(void) snprintf(p->errbuf, sizeof(p->errbuf),

View File

@ -22,7 +22,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd August 23, 2005
.Dd February 26, 2007
.Dt BPF 4
.Os
.Sh NAME
@ -305,12 +305,43 @@ This flag is initialized to zero by default.
.It Dv BIOCSSEESENT
.It Dv BIOCGSEESENT
.Pq Li u_int
These commands are obsolete but left for compatibility.
Use
.Dv BIOCSDIRECTION
and
.Dv BIOCGDIRECTION
instead.
Set or get the flag determining whether locally generated packets on the
interface should be returned by BPF.
Set to zero to see only incoming packets on the interface.
Set to one to see packets originating locally and remotely on the interface.
This flag is initialized to one by
default.
This flag is initialized to one by default.
.It Dv BIOCSDIRECTION
.It Dv BIOCGDIRECTION
.Pq Li u_int
Set or get the setting determining whether incoming, outgoing, or all packets
on the interface should be returned by BPF.
Set to
.Dv BPF_D_IN
to see only incoming packets on the interface.
Set to
.Dv BPF_D_INOUT
to see packets originating locally and remotely on the interface.
Set to
.Dv BPF_D_OUT
to see only outgoing packets on the interface.
This setting is initialized to
.Dv BPF_D_INOUT
by default.
.It Dv BIOCFEEDBACK
.Pq Li u_int
Set packet feedback mode.
This allows injected packets to be fed back as input to the interface when
output via the interface is successful.
When
.Dv BPF_D_INOUT
direction is set, injected outgoing packet is not returned by BPF to avoid
duplication. This flag is initialized to zero by default.
.It Dv BIOCLOCK
Set the locked flag on the
.Nm
@ -735,9 +766,12 @@ so desired, must utilize a filter to reject foreign packets.
Data link protocols with variable length headers are not currently supported.
.Pp
The
.Dv SEESENT
flag has been observed to work incorrectly on some interface
.Dv SEESENT ,
.Dv DIRECTION ,
and
.Dv FEEDBACK
settings have been observed to work incorrectly on some interface
types, including those with hardware loopback rather than software loopback,
and point-to-point interfaces.
It appears to function correctly on a
They appear to function correctly on a
broad range of Ethernet-style interfaces.

View File

@ -85,6 +85,8 @@ static MALLOC_DEFINE(M_BPF, "BPF", "BPF data");
#define PRINET 26 /* interruptible */
#define M_SKIP_BPF M_SKIP_FIREWALL
/*
* bpf_iflist is a list of BPF interface structures, each corresponding to a
* specific DLT. The same network interface might have several BPF interface
@ -100,8 +102,8 @@ static void bpf_attachd(struct bpf_d *, struct bpf_if *);
static void bpf_detachd(struct bpf_d *);
static void bpf_freed(struct bpf_d *);
static void bpf_mcopy(const void *, void *, size_t);
static int bpf_movein(struct uio *, int, int,
struct mbuf **, struct sockaddr *, struct bpf_insn *);
static int bpf_movein(struct uio *, int, int, struct mbuf **,
struct sockaddr *, int *, struct bpf_insn *);
static int bpf_setif(struct bpf_d *, struct ifreq *);
static void bpf_timed_out(void *);
static __inline void
@ -158,7 +160,7 @@ static struct filterops bpfread_filtops =
static int
bpf_movein(struct uio *uio, int linktype, int mtu, struct mbuf **mp,
struct sockaddr *sockp, struct bpf_insn *wfilter)
struct sockaddr *sockp, int *hdrlen, struct bpf_insn *wfilter)
{
const struct ieee80211_bpf_params *p;
struct mbuf *m;
@ -294,14 +296,8 @@ bpf_movein(struct uio *uio, int linktype, int mtu, struct mbuf **mp,
}
}
bcopy(m->m_data, sockp->sa_data, hlen);
m->m_pkthdr.len -= hlen;
m->m_len -= hlen;
#if BSD >= 199103
m->m_data += hlen; /* XXX */
#else
m->m_off += hlen;
#endif
}
*hdrlen = hlen;
return (0);
bad:
@ -403,7 +399,7 @@ bpfopen(struct cdev *dev, int flags, int fmt, struct thread *td)
dev->si_drv1 = d;
d->bd_bufsize = bpf_bufsize;
d->bd_sig = SIGIO;
d->bd_seesent = 1;
d->bd_direction = BPF_D_INOUT;
d->bd_pid = td->td_proc->p_pid;
#ifdef MAC
mac_init_bpfdesc(d);
@ -602,9 +598,9 @@ bpfwrite(struct cdev *dev, struct uio *uio, int ioflag)
{
struct bpf_d *d = dev->si_drv1;
struct ifnet *ifp;
struct mbuf *m;
int error;
struct mbuf *m, *mc;
struct sockaddr dst;
int error, hlen;
if (d->bd_bif == NULL)
return (ENXIO);
@ -619,24 +615,48 @@ bpfwrite(struct cdev *dev, struct uio *uio, int ioflag)
bzero(&dst, sizeof(dst));
error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, ifp->if_mtu,
&m, &dst, d->bd_wfilter);
&m, &dst, &hlen, d->bd_wfilter);
if (error)
return (error);
if (d->bd_hdrcmplt)
dst.sa_family = pseudo_AF_HDRCMPLT;
if (d->bd_feedback) {
mc = m_dup(m, M_DONTWAIT);
if (mc != NULL)
mc->m_pkthdr.rcvif = ifp;
/* XXX Do not return the same packet twice. */
if (d->bd_direction == BPF_D_INOUT)
m->m_flags |= M_SKIP_BPF;
} else
mc = NULL;
m->m_pkthdr.len -= hlen;
m->m_len -= hlen;
m->m_data += hlen; /* XXX */
#ifdef MAC
BPFD_LOCK(d);
mac_create_mbuf_from_bpfdesc(d, m);
if (mc != NULL)
mac_create_mbuf_from_bpfdesc(d, mc);
BPFD_UNLOCK(d);
#endif
NET_LOCK_GIANT();
error = (*ifp->if_output)(ifp, m, &dst, NULL);
NET_UNLOCK_GIANT();
/*
* The driver frees the mbuf.
*/
if (mc != NULL) {
if (error == 0) {
NET_LOCK_GIANT();
(*ifp->if_input)(ifp, mc);
NET_UNLOCK_GIANT();
} else
m_freem(mc);
}
return (error);
}
@ -679,9 +699,10 @@ reset_d(struct bpf_d *d)
* BIOCVERSION Get filter language version.
* BIOCGHDRCMPLT Get "header already complete" flag
* BIOCSHDRCMPLT Set "header already complete" flag
* BIOCGSEESENT Get "see packets sent" flag
* BIOCSSEESENT Set "see packets sent" flag
* BIOCGDIRECTION Get packet direction flag
* BIOCSDIRECTION Set packet direction flag
* BIOCLOCK Set "locked" flag
* BIOCFEEDBACK Set packet feedback mode.
*/
/* ARGSUSED */
static int
@ -713,6 +734,7 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
case BIOCVERSION:
case BIOCGRSIG:
case BIOCGHDRCMPLT:
case BIOCFEEDBACK:
case FIONREAD:
case BIOCLOCK:
case BIOCSRTIMEOUT:
@ -935,9 +957,6 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
*(u_int *)addr = d->bd_hdrcmplt;
break;
case BIOCLOCK:
d->bd_locked = 1;
break;
/*
* Set "header already complete" flag
*/
@ -946,17 +965,38 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
break;
/*
* Get "see sent packets" flag
* Get packet direction flag
*/
case BIOCGSEESENT:
*(u_int *)addr = d->bd_seesent;
case BIOCGDIRECTION:
*(u_int *)addr = d->bd_direction;
break;
/*
* Set "see sent packets" flag
* Set packet direction flag
*/
case BIOCSSEESENT:
d->bd_seesent = *(u_int *)addr;
case BIOCSDIRECTION:
{
u_int direction;
direction = *(u_int *)addr;
switch (direction) {
case BPF_D_IN:
case BPF_D_INOUT:
case BPF_D_OUT:
d->bd_direction = direction;
break;
default:
error = EINVAL;
}
}
break;
case BIOCFEEDBACK:
d->bd_feedback = *(u_int *)addr;
break;
case BIOCLOCK:
d->bd_locked = 1;
break;
case FIONBIO: /* Non-blocking I/O */
@ -1280,6 +1320,10 @@ bpf_mcopy(const void *src_arg, void *dst_arg, size_t len)
}
}
#define BPF_CHECK_DIRECTION(d, m) \
if (((d)->bd_direction == BPF_D_IN && (m)->m_pkthdr.rcvif == NULL) || \
((d)->bd_direction == BPF_D_OUT && (m)->m_pkthdr.rcvif != NULL))
/*
* Incoming linkage from device drivers, when packet is in an mbuf chain.
*/
@ -1291,13 +1335,18 @@ bpf_mtap(struct bpf_if *bp, struct mbuf *m)
int gottime;
struct timeval tv;
if (m->m_flags & M_SKIP_BPF) {
m->m_flags &= ~M_SKIP_BPF;
return;
}
gottime = 0;
pktlen = m_length(m, NULL);
BPFIF_LOCK(bp);
LIST_FOREACH(d, &bp->bif_dlist, bd_next) {
if (!d->bd_seesent && (m->m_pkthdr.rcvif == NULL))
BPF_CHECK_DIRECTION(d, m)
continue;
BPFD_LOCK(d);
++d->bd_rcount;
@ -1340,6 +1389,11 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m)
int gottime;
struct timeval tv;
if (m->m_flags & M_SKIP_BPF) {
m->m_flags &= ~M_SKIP_BPF;
return;
}
gottime = 0;
pktlen = m_length(m, NULL);
@ -1355,7 +1409,7 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m)
BPFIF_LOCK(bp);
LIST_FOREACH(d, &bp->bif_dlist, bd_next) {
if (!d->bd_seesent && (m->m_pkthdr.rcvif == NULL))
BPF_CHECK_DIRECTION(d, m)
continue;
BPFD_LOCK(d);
++d->bd_rcount;
@ -1377,6 +1431,8 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m)
BPFIF_UNLOCK(bp);
}
#undef BPF_CHECK_DIRECTION
/*
* Move the packet data from interface memory (pkt) into the
* store buffer. "cpfn" is the routine called to do the actual data
@ -1693,7 +1749,8 @@ bpfstats_fill_xbpf(struct xbpf_d *d, struct bpf_d *bd)
d->bd_immediate = bd->bd_immediate;
d->bd_promisc = bd->bd_promisc;
d->bd_hdrcmplt = bd->bd_hdrcmplt;
d->bd_seesent = bd->bd_seesent;
d->bd_direction = bd->bd_direction;
d->bd_feedback = bd->bd_feedback;
d->bd_async = bd->bd_async;
d->bd_rcount = bd->bd_rcount;
d->bd_dcount = bd->bd_dcount;

View File

@ -109,12 +109,24 @@ struct bpf_version {
#define BIOCSRSIG _IOW('B',115, u_int)
#define BIOCGHDRCMPLT _IOR('B',116, u_int)
#define BIOCSHDRCMPLT _IOW('B',117, u_int)
#define BIOCGSEESENT _IOR('B',118, u_int)
#define BIOCSSEESENT _IOW('B',119, u_int)
#define BIOCGDIRECTION _IOR('B',118, u_int)
#define BIOCSDIRECTION _IOW('B',119, u_int)
#define BIOCSDLT _IOW('B',120, u_int)
#define BIOCGDLTLIST _IOWR('B',121, struct bpf_dltlist)
#define BIOCLOCK _IO('B', 122)
#define BIOCSETWF _IOW('B',123, struct bpf_program)
#define BIOCFEEDBACK _IOW('B',124, u_int)
/* Obsolete */
#define BIOCGSEESENT BIOCGDIRECTION
#define BIOCSSEESENT BIOCSDIRECTION
/* Packet directions */
enum bpf_direction {
BPF_D_IN, /* See incoming packets */
BPF_D_INOUT, /* See incoming and outgoing packets */
BPF_D_OUT /* See outgoing packets */
};
/*
* Structure prepended to each packet.

View File

@ -81,7 +81,8 @@ struct bpf_d {
u_char bd_state; /* idle, waiting, or timed out */
u_char bd_immediate; /* true to return on packet arrival */
int bd_hdrcmplt; /* false to fill in src lladdr automatically */
int bd_seesent; /* true if bpf should see sent packets */
int bd_direction; /* select packet direction */
int bd_feedback; /* true to feed back sent packets */
int bd_async; /* non-zero if packet reception should generate signal */
int bd_sig; /* signal to send upon packet reception */
struct sigio * bd_sigio; /* information for async I/O */
@ -119,7 +120,8 @@ struct xbpf_d {
u_char bd_promisc;
u_char bd_immediate;
int bd_hdrcmplt;
int bd_seesent;
int bd_direction;
int bd_feedback;
int bd_async;
u_long bd_rcount;
u_long bd_dcount;

View File

@ -34,6 +34,7 @@
#include <net/if.h>
#include <net/if_var.h>
#include <net/bpf.h>
#include <net/bpfdesc.h>
#include <arpa/inet.h>
@ -76,7 +77,9 @@ bpf_flags(struct xbpf_d *bd, char *flagbuf)
*flagbuf++ = bd->bd_promisc ? 'p' : '-';
*flagbuf++ = bd->bd_immediate ? 'i' : '-';
*flagbuf++ = bd->bd_hdrcmplt ? '-' : 'f';
*flagbuf++ = bd->bd_seesent ? 's' : '-';
*flagbuf++ = (bd->bd_direction == BPF_D_IN) ? '-' :
((bd->bd_direction == BPF_D_OUT) ? 'o' : 's');
*flagbuf++ = bd->bd_feedback ? 'b' : '-';
*flagbuf++ = bd->bd_async ? 'a' : '-';
*flagbuf++ = bd->bd_locked ? 'l' : '-';
*flagbuf++ = '\0';
@ -107,7 +110,7 @@ bpf_stats(char *ifname)
free(bd);
return;
}
printf("%5s %6s %6s %9s %9s %9s %5s %5s %s\n",
printf("%5s %6s %7s %9s %9s %9s %5s %5s %s\n",
"Pid", "Netif", "Flags", "Recv", "Drop", "Match", "Sblen",
"Hblen", "Command");
for (d = &bd[0]; d < &bd[size / sizeof(*d)]; d++) {
@ -115,7 +118,7 @@ bpf_stats(char *ifname)
continue;
bpf_flags(d, flagbuf);
pname = bpf_pidname(d->bd_pid);
printf("%5d %6s %6s %9lu %9lu %9lu %5d %5d %s\n",
printf("%5d %6s %7s %9lu %9lu %9lu %5d %5d %s\n",
d->bd_pid, d->bd_ifname, flagbuf,
d->bd_rcount, d->bd_dcount, d->bd_fcount,
d->bd_slen, d->bd_hlen, pname);