summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/libpcap/pcap-bpf.c19
-rw-r--r--share/man/man4/bpf.446
-rw-r--r--sys/net/bpf.c119
-rw-r--r--sys/net/bpf.h16
-rw-r--r--sys/net/bpfdesc.h6
-rw-r--r--usr.bin/netstat/bpf.c9
6 files changed, 168 insertions, 47 deletions
diff --git a/contrib/libpcap/pcap-bpf.c b/contrib/libpcap/pcap-bpf.c
index 863827f..e8492d3 100644
--- a/contrib/libpcap/pcap-bpf.c
+++ b/contrib/libpcap/pcap-bpf.c
@@ -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),
diff --git a/share/man/man4/bpf.4 b/share/man/man4/bpf.4
index 9911a63..bb27858 100644
--- a/share/man/man4/bpf.4
+++ b/share/man/man4/bpf.4
@@ -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.
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index 9292236..728bac2 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -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;
diff --git a/sys/net/bpf.h b/sys/net/bpf.h
index 3bec119..871087b 100644
--- a/sys/net/bpf.h
+++ b/sys/net/bpf.h
@@ -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.
diff --git a/sys/net/bpfdesc.h b/sys/net/bpfdesc.h
index 0edcaf6..7db0e12 100644
--- a/sys/net/bpfdesc.h
+++ b/sys/net/bpfdesc.h
@@ -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;
diff --git a/usr.bin/netstat/bpf.c b/usr.bin/netstat/bpf.c
index f5cda6a..90fa623d 100644
--- a/usr.bin/netstat/bpf.c
+++ b/usr.bin/netstat/bpf.c
@@ -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);
OpenPOWER on IntegriCloud