summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorjkim <jkim@FreeBSD.org>2007-02-26 22:24:14 +0000
committerjkim <jkim@FreeBSD.org>2007-02-26 22:24:14 +0000
commit2bd7382fdc16aa04088cebb691546535c56c484b (patch)
tree8efb23bc3668968e694845b80771f494e428f138 /sys/net
parentfdcdf27f8008b78cf159fbc5e87092ebded35ab3 (diff)
downloadFreeBSD-src-2bd7382fdc16aa04088cebb691546535c56c484b.zip
FreeBSD-src-2bd7382fdc16aa04088cebb691546535c56c484b.tar.gz
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
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/bpf.c119
-rw-r--r--sys/net/bpf.h16
-rw-r--r--sys/net/bpfdesc.h6
3 files changed, 106 insertions, 35 deletions
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;
OpenPOWER on IntegriCloud