summaryrefslogtreecommitdiffstats
path: root/sys/net/bpf.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/bpf.c')
-rw-r--r--sys/net/bpf.c119
1 files changed, 88 insertions, 31 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;
OpenPOWER on IntegriCloud