Index: contrib/libpcap/pcap-bpf.c =================================================================== RCS file: /home/ncvs/src/contrib/libpcap/pcap-bpf.c,v retrieving revision 1.2 diff -u -r1.2 pcap-bpf.c --- contrib/libpcap/pcap-bpf.c 4 Sep 2006 20:12:45 -0000 1.2 +++ contrib/libpcap/pcap-bpf.c 14 Feb 2007 22:30:47 -0000 @@ -1093,9 +1093,35 @@ static int pcap_setdirection_bpf(pcap_t *p, pcap_direction_t d) { -#ifdef BIOCSSEESENT +#if defined(BIOCSDIRECTION) + u_int direction; + + switch (d) { + case PCAP_D_IN: + direction = BPF_D_IN; + break; + case PCAP_D_INOUT: + direction = BPF_D_INOUT; + break; + case PCAP_D_OUT: + direction = BPF_D_OUT; + break; + default: + (void) snprintf(p->errbuf, sizeof(p->errbuf), + "Cannot set unsupported direction"); + return (-1); + } + 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_INOUT) ? "PCAP_D_INOUT" : "PCAP_D_OUT", + strerror(errno)); + return (-1); + } + return (0); +#elif defined(BIOCSSEESENT) u_int seesent; -#endif /* * We don't support PCAP_D_OUT. @@ -1105,7 +1131,7 @@ "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), Index: share/man/man4/bpf.4 =================================================================== RCS file: /home/ncvs/src/share/man/man4/bpf.4,v retrieving revision 1.47 diff -u -r1.47 bpf.4 --- share/man/man4/bpf.4 18 Nov 2005 10:52:22 -0000 1.47 +++ share/man/man4/bpf.4 14 Feb 2007 21:57:40 -0000 @@ -22,7 +22,7 @@ .\" .\" $FreeBSD: src/share/man/man4/bpf.4,v 1.47 2005/11/18 10:52:22 ru Exp $ .\" -.Dd August 23, 2005 +.Dd February 14, 2007 .Dt BPF 4 .Os .Sh NAME @@ -305,12 +305,28 @@ .It Dv BIOCSSEESENT .It Dv BIOCGSEESENT .Pq Li u_int +These commands are obsolete but left for compatibility. +Use BIOCSDIRECTION and 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 flag determining whether incoming, outgoing, or all 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. +Set to two to see only outgoing packets on the interface. +This flag is initialized to one by default. +.It Dv BIOCFEEDBACK +.Pq Li u_int +Set the packet feedback mode. +This allows the injected packets are fed back to the same interface as if they +are remotely generated. +This flag is initialized to zero by default. .It Dv BIOCLOCK Set the locked flag on the .Nm @@ -735,9 +751,12 @@ 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 +flags 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. Index: sys/net/bpf.c =================================================================== RCS file: /home/ncvs/src/sys/net/bpf.c,v retrieving revision 1.175 diff -u -r1.175 bpf.c --- sys/net/bpf.c 28 Jan 2007 16:38:44 -0000 1.175 +++ sys/net/bpf.c 14 Feb 2007 21:57:40 -0000 @@ -85,6 +85,8 @@ #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_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 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 @@ } } 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 @@ 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 @@ { 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,46 @@ 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); 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 +697,10 @@ * 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 +732,7 @@ case BIOCVERSION: case BIOCGRSIG: case BIOCGHDRCMPLT: + case BIOCFEEDBACK: case FIONREAD: case BIOCLOCK: case BIOCSRTIMEOUT: @@ -935,9 +955,6 @@ *(u_int *)addr = d->bd_hdrcmplt; break; - case BIOCLOCK: - d->bd_locked = 1; - break; /* * Set "header already complete" flag */ @@ -946,17 +963,38 @@ 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 +1318,10 @@ } } +#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 +1333,18 @@ 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; @@ -1325,6 +1372,8 @@ BPFD_UNLOCK(d); } BPFIF_UNLOCK(bp); + + m->m_flags &= ~M_SKIP_BPF; } /* @@ -1340,6 +1389,11 @@ 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 @@ 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 @@ 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 @@ 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; Index: sys/net/bpf.h =================================================================== RCS file: /home/ncvs/src/sys/net/bpf.h,v retrieving revision 1.46 diff -u -r1.46 bpf.h --- sys/net/bpf.h 4 Sep 2006 19:24:34 -0000 1.46 +++ sys/net/bpf.h 14 Feb 2007 21:57:41 -0000 @@ -109,12 +109,22 @@ #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 direction flags */ +#define BPF_D_IN 0 /* See incoming packets */ +#define BPF_D_INOUT 1 /* See incoming/outgoing packets */ +#define BPF_D_OUT 2 /* See outgoing packets */ /* * Structure prepended to each packet. Index: sys/net/bpfdesc.h =================================================================== RCS file: /home/ncvs/src/sys/net/bpfdesc.h,v retrieving revision 1.36 diff -u -r1.36 bpfdesc.h --- sys/net/bpfdesc.h 29 Jan 2007 14:41:03 -0000 1.36 +++ sys/net/bpfdesc.h 14 Feb 2007 21:57:41 -0000 @@ -81,7 +81,8 @@ 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 @@ 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; Index: usr.bin/netstat/bpf.c =================================================================== RCS file: /home/ncvs/src/usr.bin/netstat/bpf.c,v retrieving revision 1.7 diff -u -r1.7 bpf.c --- usr.bin/netstat/bpf.c 27 Nov 2006 19:50:50 -0000 1.7 +++ usr.bin/netstat/bpf.c 14 Feb 2007 21:57:41 -0000 @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -76,7 +77,17 @@ *flagbuf++ = bd->bd_promisc ? 'p' : '-'; *flagbuf++ = bd->bd_immediate ? 'i' : '-'; *flagbuf++ = bd->bd_hdrcmplt ? '-' : 'f'; - *flagbuf++ = bd->bd_seesent ? 's' : '-'; + switch (bd->bd_direction) { + case BPF_D_INOUT: + *flagbuf++ = 's'; + break; + case BPF_D_OUT: + *flagbuf++ = 'o'; + break; + default: + *flagbuf++ = '-'; + } + *flagbuf++ = bd->bd_feedback ? 'b' : '-'; *flagbuf++ = bd->bd_async ? 'a' : '-'; *flagbuf++ = bd->bd_locked ? 'l' : '-'; *flagbuf++ = '\0'; @@ -107,7 +118,7 @@ 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 +126,7 @@ 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);