diff options
Diffstat (limited to 'sys/net/bpf.c')
-rw-r--r-- | sys/net/bpf.c | 263 |
1 files changed, 205 insertions, 58 deletions
diff --git a/sys/net/bpf.c b/sys/net/bpf.c index 16245c9..ab2ba1f 100644 --- a/sys/net/bpf.c +++ b/sys/net/bpf.c @@ -90,12 +90,16 @@ MALLOC_DEFINE(M_BPF, "BPF", "BPF data"); #define PRINET 26 /* interruptible */ +#define SIZEOF_BPF_HDR(type) \ + (offsetof(type, bh_hdrlen) + sizeof(((type *)0)->bh_hdrlen)) + #ifdef COMPAT_FREEBSD32 #include <sys/mount.h> #include <compat/freebsd32/freebsd32.h> #define BPF_ALIGNMENT32 sizeof(int32_t) #define BPF_WORDALIGN32(x) (((x)+(BPF_ALIGNMENT32-1))&~(BPF_ALIGNMENT32-1)) +#ifndef BURN_BRIDGES /* * 32-bit version of structure prepended to each packet. We use this header * instead of the standard one for 32-bit streams. We mark the a stream as @@ -108,6 +112,7 @@ struct bpf_hdr32 { uint16_t bh_hdrlen; /* length of bpf header (this struct plus alignment padding) */ }; +#endif struct bpf_program32 { u_int bf_len; @@ -120,11 +125,11 @@ struct bpf_dltlist32 { }; #define BIOCSETF32 _IOW('B', 103, struct bpf_program32) -#define BIOCSRTIMEOUT32 _IOW('B',109, struct timeval32) -#define BIOCGRTIMEOUT32 _IOR('B',110, struct timeval32) -#define BIOCGDLTLIST32 _IOWR('B',121, struct bpf_dltlist32) -#define BIOCSETWF32 _IOW('B',123, struct bpf_program32) -#define BIOCSETFNR32 _IOW('B',130, struct bpf_program32) +#define BIOCSRTIMEOUT32 _IOW('B', 109, struct timeval32) +#define BIOCGRTIMEOUT32 _IOR('B', 110, struct timeval32) +#define BIOCGDLTLIST32 _IOWR('B', 121, struct bpf_dltlist32) +#define BIOCSETWF32 _IOW('B', 123, struct bpf_program32) +#define BIOCSETFNR32 _IOW('B', 130, struct bpf_program32) #endif /* @@ -148,7 +153,7 @@ static __inline void bpf_wakeup(struct bpf_d *); static void catchpacket(struct bpf_d *, u_char *, u_int, u_int, void (*)(struct bpf_d *, caddr_t, u_int, void *, u_int), - struct timeval *); + struct bintime *); static void reset_d(struct bpf_d *); static int bpf_setf(struct bpf_d *, struct bpf_program *, u_long cmd); static int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *); @@ -1007,6 +1012,8 @@ reset_d(struct bpf_d *d) * BIOCSHDRCMPLT Set "header already complete" flag * BIOCGDIRECTION Get packet direction flag * BIOCSDIRECTION Set packet direction flag + * BIOCGTSTAMP Get time stamp format and resolution. + * BIOCSTSTAMP Set time stamp format and resolution. * BIOCLOCK Set "locked" flag * BIOCFEEDBACK Set packet feedback mode. * BIOCSETZBUF Set current zero-copy buffer locations. @@ -1055,6 +1062,7 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, case BIOCVERSION: case BIOCGRSIG: case BIOCGHDRCMPLT: + case BIOCSTSTAMP: case BIOCFEEDBACK: case FIONREAD: case BIOCLOCK: @@ -1383,6 +1391,28 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, } break; + /* + * Set packet timestamp format and resolution. + */ + case BIOCGTSTAMP: + *(u_int *)addr = d->bd_tstamp; + break; + + /* + * Set packet timestamp format and resolution. + */ + case BIOCSTSTAMP: + { + u_int func; + + func = *(u_int *)addr; + if (BPF_T_VALID(func)) + d->bd_tstamp = func; + else + error = EINVAL; + } + break; + case BIOCFEEDBACK: d->bd_feedback = *(u_int *)addr; break; @@ -1729,6 +1759,48 @@ filt_bpfread(struct knote *kn, long hint) return (ready); } +#define BPF_TSTAMP_NONE 0 +#define BPF_TSTAMP_FAST 1 +#define BPF_TSTAMP_NORMAL 2 +#define BPF_TSTAMP_EXTERN 3 + +static int +bpf_ts_quality(int tstype) +{ + + if (tstype == BPF_T_NONE) + return (BPF_TSTAMP_NONE); + if ((tstype & BPF_T_FAST) != 0) + return (BPF_TSTAMP_FAST); + + return (BPF_TSTAMP_NORMAL); +} + +static int +bpf_gettime(struct bintime *bt, int tstype, struct mbuf *m) +{ + struct m_tag *tag; + int quality; + + quality = bpf_ts_quality(tstype); + if (quality == BPF_TSTAMP_NONE) + return (quality); + + if (m != NULL) { + tag = m_tag_locate(m, MTAG_BPF, MTAG_BPF_TIMESTAMP, NULL); + if (tag != NULL) { + *bt = *(struct bintime *)(tag + 1); + return (BPF_TSTAMP_EXTERN); + } + } + if (quality == BPF_TSTAMP_NORMAL) + binuptime(bt); + else + getbinuptime(bt); + + return (quality); +} + /* * Incoming linkage from device drivers. Process the packet pkt, of length * pktlen, which is stored in a contiguous buffer. The packet is parsed @@ -1738,15 +1810,15 @@ filt_bpfread(struct knote *kn, long hint) void bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) { + struct bintime bt; struct bpf_d *d; #ifdef BPF_JITTER bpf_jit_filter *bf; #endif u_int slen; int gottime; - struct timeval tv; - gottime = 0; + gottime = BPF_TSTAMP_NONE; BPFIF_LOCK(bp); LIST_FOREACH(d, &bp->bif_dlist, bd_next) { BPFD_LOCK(d); @@ -1766,15 +1838,13 @@ bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) slen = bpf_filter(d->bd_rfilter, pkt, pktlen, pktlen); if (slen != 0) { d->bd_fcount++; - if (!gottime) { - microtime(&tv); - gottime = 1; - } + if (gottime < bpf_ts_quality(d->bd_tstamp)) + gottime = bpf_gettime(&bt, d->bd_tstamp, NULL); #ifdef MAC if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) #endif catchpacket(d, pkt, pktlen, slen, - bpf_append_bytes, &tv); + bpf_append_bytes, &bt); } BPFD_UNLOCK(d); } @@ -1791,13 +1861,13 @@ bpf_tap(struct bpf_if *bp, u_char *pkt, u_int pktlen) void bpf_mtap(struct bpf_if *bp, struct mbuf *m) { + struct bintime bt; struct bpf_d *d; #ifdef BPF_JITTER bpf_jit_filter *bf; #endif u_int pktlen, slen; int gottime; - struct timeval tv; /* Skip outgoing duplicate packets. */ if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { @@ -1805,10 +1875,9 @@ bpf_mtap(struct bpf_if *bp, struct mbuf *m) return; } - gottime = 0; - pktlen = m_length(m, NULL); + gottime = BPF_TSTAMP_NONE; BPFIF_LOCK(bp); LIST_FOREACH(d, &bp->bif_dlist, bd_next) { if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif, bp->bif_ifp)) @@ -1825,15 +1894,13 @@ bpf_mtap(struct bpf_if *bp, struct mbuf *m) slen = bpf_filter(d->bd_rfilter, (u_char *)m, pktlen, 0); if (slen != 0) { d->bd_fcount++; - if (!gottime) { - microtime(&tv); - gottime = 1; - } + if (gottime < bpf_ts_quality(d->bd_tstamp)) + gottime = bpf_gettime(&bt, d->bd_tstamp, m); #ifdef MAC if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) #endif catchpacket(d, (u_char *)m, pktlen, slen, - bpf_append_mbuf, &tv); + bpf_append_mbuf, &bt); } BPFD_UNLOCK(d); } @@ -1847,11 +1914,11 @@ bpf_mtap(struct bpf_if *bp, struct mbuf *m) void bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) { + struct bintime bt; struct mbuf mb; struct bpf_d *d; u_int pktlen, slen; int gottime; - struct timeval tv; /* Skip outgoing duplicate packets. */ if ((m->m_flags & M_PROMISC) != 0 && m->m_pkthdr.rcvif == NULL) { @@ -1859,8 +1926,6 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) return; } - gottime = 0; - pktlen = m_length(m, NULL); /* * Craft on-stack mbuf suitable for passing to bpf_filter. @@ -1872,6 +1937,7 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) mb.m_len = dlen; pktlen += dlen; + gottime = BPF_TSTAMP_NONE; BPFIF_LOCK(bp); LIST_FOREACH(d, &bp->bif_dlist, bd_next) { if (BPF_CHECK_DIRECTION(d, m->m_pkthdr.rcvif, bp->bif_ifp)) @@ -1881,15 +1947,13 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) slen = bpf_filter(d->bd_rfilter, (u_char *)&mb, pktlen, 0); if (slen != 0) { d->bd_fcount++; - if (!gottime) { - microtime(&tv); - gottime = 1; - } + if (gottime < bpf_ts_quality(d->bd_tstamp)) + gottime = bpf_gettime(&bt, d->bd_tstamp, m); #ifdef MAC if (mac_bpfdesc_check_receive(d, bp->bif_ifp) == 0) #endif catchpacket(d, (u_char *)&mb, pktlen, slen, - bpf_append_mbuf, &tv); + bpf_append_mbuf, &bt); } BPFD_UNLOCK(d); } @@ -1898,6 +1962,69 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) #undef BPF_CHECK_DIRECTION +#undef BPF_TSTAMP_NONE +#undef BPF_TSTAMP_FAST +#undef BPF_TSTAMP_NORMAL +#undef BPF_TSTAMP_EXTERN + +static int +bpf_hdrlen(struct bpf_d *d) +{ + int hdrlen; + + hdrlen = d->bd_bif->bif_hdrlen; +#ifndef BURN_BRIDGES + if (d->bd_tstamp == BPF_T_NONE || + BPF_T_FORMAT(d->bd_tstamp) == BPF_T_MICROTIME) +#ifdef COMPAT_FREEBSD32 + if (d->bd_compat32) + hdrlen += SIZEOF_BPF_HDR(struct bpf_hdr32); + else +#endif + hdrlen += SIZEOF_BPF_HDR(struct bpf_hdr); + else +#endif + hdrlen += SIZEOF_BPF_HDR(struct bpf_xhdr); +#ifdef COMPAT_FREEBSD32 + if (d->bd_compat32) + hdrlen = BPF_WORDALIGN32(hdrlen); + else +#endif + hdrlen = BPF_WORDALIGN(hdrlen); + + return (hdrlen - d->bd_bif->bif_hdrlen); +} + +static void +bpf_bintime2ts(struct bintime *bt, struct bpf_ts *ts, int tstype) +{ + struct bintime bt2; + struct timeval tsm; + struct timespec tsn; + + if ((tstype & BPF_T_MONOTONIC) == 0) { + bt2 = *bt; + bintime_add(&bt2, &boottimebin); + bt = &bt2; + } + switch (BPF_T_FORMAT(tstype)) { + case BPF_T_MICROTIME: + bintime2timeval(bt, &tsm); + ts->bt_sec = tsm.tv_sec; + ts->bt_frac = tsm.tv_usec; + break; + case BPF_T_NANOTIME: + bintime2timespec(bt, &tsn); + ts->bt_sec = tsn.tv_sec; + ts->bt_frac = tsn.tv_nsec; + break; + case BPF_T_BINTIME: + ts->bt_sec = bt->sec; + ts->bt_frac = bt->frac; + break; + } +} + /* * Move the packet data from interface memory (pkt) into the * store buffer. "cpfn" is the routine called to do the actual data @@ -1908,15 +2035,19 @@ bpf_mtap2(struct bpf_if *bp, void *data, u_int dlen, struct mbuf *m) static void catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen, void (*cpfn)(struct bpf_d *, caddr_t, u_int, void *, u_int), - struct timeval *tv) + struct bintime *bt) { - struct bpf_hdr hdr; + struct bpf_xhdr hdr; +#ifndef BURN_BRIDGES + struct bpf_hdr hdr_old; #ifdef COMPAT_FREEBSD32 - struct bpf_hdr32 hdr32; + struct bpf_hdr32 hdr32_old; #endif - int totlen, curlen; - int hdrlen = d->bd_bif->bif_hdrlen; +#endif + int caplen, curlen, hdrlen, totlen; int do_wakeup = 0; + int do_timestamp; + int tstype; BPFD_LOCK_ASSERT(d); @@ -1940,6 +2071,7 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen, * much. Otherwise, transfer the whole packet (unless * we hit the buffer size limit). */ + hdrlen = bpf_hdrlen(d); totlen = hdrlen + min(snaplen, pktlen); if (totlen > d->bd_bufsize) totlen = d->bd_bufsize; @@ -1979,19 +2111,39 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen, * reader should be woken up. */ do_wakeup = 1; + caplen = totlen - hdrlen; + tstype = d->bd_tstamp; + do_timestamp = tstype != BPF_T_NONE; +#ifndef BURN_BRIDGES + if (tstype == BPF_T_NONE || BPF_T_FORMAT(tstype) == BPF_T_MICROTIME) { + struct bpf_ts ts; + if (do_timestamp) + bpf_bintime2ts(bt, &ts, tstype); #ifdef COMPAT_FREEBSD32 - /* - * If this is a 32-bit stream, then stick a 32-bit header at the - * front and copy the data into the buffer. - */ - if (d->bd_compat32) { - bzero(&hdr32, sizeof(hdr32)); - hdr32.bh_tstamp.tv_sec = tv->tv_sec; - hdr32.bh_tstamp.tv_usec = tv->tv_usec; - hdr32.bh_datalen = pktlen; - hdr32.bh_hdrlen = hdrlen; - hdr.bh_caplen = hdr32.bh_caplen = totlen - hdrlen; - bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr32, sizeof(hdr32)); + if (d->bd_compat32) { + bzero(&hdr32_old, sizeof(hdr32_old)); + if (do_timestamp) { + hdr32_old.bh_tstamp.tv_sec = ts.bt_sec; + hdr32_old.bh_tstamp.tv_usec = ts.bt_frac; + } + hdr32_old.bh_datalen = pktlen; + hdr32_old.bh_hdrlen = hdrlen; + hdr32_old.bh_caplen = caplen; + bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr32_old, + sizeof(hdr32_old)); + goto copy; + } +#endif + bzero(&hdr_old, sizeof(hdr_old)); + if (do_timestamp) { + hdr_old.bh_tstamp.tv_sec = ts.bt_sec; + hdr_old.bh_tstamp.tv_usec = ts.bt_frac; + } + hdr_old.bh_datalen = pktlen; + hdr_old.bh_hdrlen = hdrlen; + hdr_old.bh_caplen = caplen; + bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr_old, + sizeof(hdr_old)); goto copy; } #endif @@ -2001,19 +2153,20 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen, * move forward the length of the header plus padding. */ bzero(&hdr, sizeof(hdr)); - hdr.bh_tstamp = *tv; + if (do_timestamp) + bpf_bintime2ts(bt, &hdr.bh_tstamp, tstype); hdr.bh_datalen = pktlen; hdr.bh_hdrlen = hdrlen; - hdr.bh_caplen = totlen - hdrlen; + hdr.bh_caplen = caplen; bpf_append_bytes(d, d->bd_sbuf, curlen, &hdr, sizeof(hdr)); /* * Copy the packet data into the store buffer and update its length. */ -#ifdef COMPAT_FREEBSD32 - copy: +#ifndef BURN_BRIDGES +copy: #endif - (*cpfn)(d, d->bd_sbuf, curlen + hdrlen, pkt, hdr.bh_caplen); + (*cpfn)(d, d->bd_sbuf, curlen + hdrlen, pkt, caplen); d->bd_slen = curlen + totlen; if (do_wakeup) @@ -2083,13 +2236,7 @@ bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp) LIST_INSERT_HEAD(&bpf_iflist, bp, bif_next); mtx_unlock(&bpf_mtx); - /* - * Compute the length of the bpf header. This is not necessarily - * equal to SIZEOF_BPF_HDR because we want to insert spacing such - * that the network layer header begins on a longword boundary (for - * performance reasons and to alleviate alignment restrictions). - */ - bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen; + bp->bif_hdrlen = hdrlen; if (bootverbose) if_printf(ifp, "bpf attached\n"); |