X-Git-Url: https://git.tcpdump.org/libpcap/blobdiff_plain/28f1b2074cba0c89c3ccbcf0d359f86d6519a73e..HEAD:/pcap-netmap.c diff --git a/pcap-netmap.c b/pcap-netmap.c index cd856fe3..56a6bc41 100644 --- a/pcap-netmap.c +++ b/pcap-netmap.c @@ -24,18 +24,16 @@ * SUCH DAMAGE. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +#include #include -#include #include #include #include #include #include #include +#include #define NETMAP_WITH_LIBS #include @@ -43,12 +41,15 @@ #include "pcap-int.h" #include "pcap-netmap.h" -#if defined (linux) -/* On FreeBSD we use IFF_PPROMISC which is in ifr_flagshigh. - * remap to IFF_PROMISC on linux - */ -#define IFF_PPROMISC IFF_PROMISC -#endif /* linux */ +#ifndef __FreeBSD__ + /* + * On FreeBSD we use IFF_PPROMISC which is in ifr_flagshigh. + * Remap to IFF_PROMISC on other platforms. + * + * XXX - DragonFly BSD? + */ + #define IFF_PPROMISC IFF_PROMISC +#endif /* __FreeBSD__ */ struct pcap_netmap { struct nm_desc *d; /* pointer returned by nm_open() */ @@ -64,7 +65,7 @@ pcap_netmap_stats(pcap_t *p, struct pcap_stat *ps) { struct pcap_netmap *pn = p->priv; - ps->ps_recv = pn->rx_pkts; + ps->ps_recv = (u_int)pn->rx_pkts; ps->ps_drop = 0; ps->ps_ifdrop = 0; return 0; @@ -79,7 +80,7 @@ pcap_netmap_filter(u_char *arg, struct pcap_pkthdr *h, const u_char *buf) const struct bpf_insn *pc = p->fcode.bf_insns; ++pn->rx_pkts; - if (pc == NULL || bpf_filter(pc, buf, h->len, h->caplen)) + if (pc == NULL || pcapint_filter(pc, buf, h->len, h->caplen)) pn->cb(pn->cb_arg, h, buf); } @@ -114,7 +115,7 @@ pcap_netmap_dispatch(pcap_t *p, int cnt, pcap_handler cb, u_char *user) /* XXX need to check the NIOCTXSYNC/poll */ static int -pcap_netmap_inject(pcap_t *p, const void *buf, size_t size) +pcap_netmap_inject(pcap_t *p, const void *buf, int size) { struct pcap_netmap *pn = p->priv; struct nm_desc *d = pn->d; @@ -131,19 +132,40 @@ pcap_netmap_ioctl(pcap_t *p, u_long what, uint32_t *if_flags) struct ifreq ifr; int error, fd = d->fd; -#ifdef linux +#ifdef __linux__ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { fprintf(stderr, "Error: cannot get device control socket.\n"); return -1; } -#endif /* linux */ +#endif /* __linux__ */ bzero(&ifr, sizeof(ifr)); - strncpy(ifr.ifr_name, d->req.nr_name, sizeof(ifr.ifr_name)); + /* + * ifreq.ifr_name and nmreq.nr_name have the same size and both + * contain a NUL-terminated string. + */ + (void)pcapint_strlcpy(ifr.ifr_name, d->req.nr_name, sizeof(ifr.ifr_name)); switch (what) { case SIOCSIFFLAGS: - ifr.ifr_flags = *if_flags; + /* + * The flags we pass in are 32-bit and unsigned. + * + * On most if not all UN*Xes, ifr_flags is 16-bit and + * signed, and the result of assigning a longer + * unsigned value to a shorter signed value is + * implementation-defined (even if, in practice, it'll + * do what's intended on all platforms we support + * result of assigning a 32-bit unsigned value). + * So we mask out the upper 16 bits. + */ + ifr.ifr_flags = *if_flags & 0xffff; #ifdef __FreeBSD__ + /* + * In FreeBSD, we need to set the high-order flags, + * as we're using IFF_PPROMISC, which is in those bits. + * + * XXX - DragonFly BSD? + */ ifr.ifr_flagshigh = *if_flags >> 16; #endif /* __FreeBSD__ */ break; @@ -152,15 +174,32 @@ pcap_netmap_ioctl(pcap_t *p, u_long what, uint32_t *if_flags) if (!error) { switch (what) { case SIOCGIFFLAGS: - *if_flags = ifr.ifr_flags; + /* + * The flags we return are 32-bit. + * + * On most if not all UN*Xes, ifr_flags is + * 16-bit and signed, and will get sign- + * extended, so that the upper 16 bits of + * those flags will be forced on. So we + * mask out the upper 16 bits of the + * sign-extended value. + */ + *if_flags = ifr.ifr_flags & 0xffff; #ifdef __FreeBSD__ + /* + * In FreeBSD, we need to return the + * high-order flags, as we're using + * IFF_PPROMISC, which is in those bits. + * + * XXX - DragonFly BSD? + */ *if_flags |= (ifr.ifr_flagshigh << 16); #endif /* __FreeBSD__ */ } } -#ifdef linux +#ifdef __linux__ close(fd); -#endif /* linux */ +#endif /* __linux__ */ return error ? -1 : 0; } @@ -180,7 +219,7 @@ pcap_netmap_close(pcap_t *p) } } nm_close(d); - pcap_cleanup_live_common(p); + pcapint_cleanup_live_common(p); } @@ -188,22 +227,36 @@ static int pcap_netmap_activate(pcap_t *p) { struct pcap_netmap *pn = p->priv; - struct nm_desc *d = nm_open(p->opt.device, NULL, 0, NULL); + struct nm_desc *d; uint32_t if_flags = 0; + d = nm_open(p->opt.device, NULL, 0, NULL); if (d == NULL) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "netmap open: cannot access %s: %s\n", - p->opt.device, pcap_strerror(errno)); - pcap_cleanup_live_common(p); + pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, + errno, "netmap open: cannot access %s", + p->opt.device); + pcapint_cleanup_live_common(p); return (PCAP_ERROR); } - if (0) - fprintf(stderr, "%s device %s priv %p fd %d ports %d..%d\n", - __FUNCTION__, p->opt.device, d, d->fd, - d->first_rx_ring, d->last_rx_ring); +#if 0 + fprintf(stderr, "%s device %s priv %p fd %d ports %d..%d\n", + __func__, p->opt.device, d, d->fd, + d->first_rx_ring, d->last_rx_ring); +#endif pn->d = d; p->fd = d->fd; + + /* + * Turn a negative snapshot value (invalid), a snapshot value of + * 0 (unspecified), or a value bigger than the normal maximum + * value, into the maximum allowed value. + * + * If some application really *needs* a bigger snapshot + * length, we should just increase MAXIMUM_SNAPLEN. + */ + if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN) + p->snapshot = MAXIMUM_SNAPLEN; + if (p->opt.promisc && !(d->req.nr_ringid & NETMAP_SW_RING)) { pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */ if (!(if_flags & IFF_PPROMISC)) { @@ -215,12 +268,12 @@ pcap_netmap_activate(pcap_t *p) p->linktype = DLT_EN10MB; p->selectable_fd = p->fd; p->read_op = pcap_netmap_dispatch; - p->inject_op = pcap_netmap_inject, - p->setfilter_op = install_bpf_program; + p->inject_op = pcap_netmap_inject; + p->setfilter_op = pcapint_install_bpf_program; p->setdirection_op = NULL; p->set_datalink_op = NULL; - p->getnonblock_op = pcap_getnonblock_fd; - p->setnonblock_op = pcap_setnonblock_fd; + p->getnonblock_op = pcapint_getnonblock_fd; + p->setnonblock_op = pcapint_setnonblock_fd; p->stats_op = pcap_netmap_stats; p->cleanup_op = pcap_netmap_close; @@ -236,7 +289,7 @@ pcap_netmap_create(const char *device, char *ebuf, int *is_ours) *is_ours = (!strncmp(device, "netmap:", 7) || !strncmp(device, "vale", 4)); if (! *is_ours) return NULL; - p = pcap_create_common(ebuf, sizeof (struct pcap_netmap)); + p = PCAP_CREATE_COMMON(ebuf, struct pcap_netmap); if (p == NULL) return (NULL); p->activate_op = pcap_netmap_activate;