diff options
Diffstat (limited to 'contrib/libpcap/pcap-snf.c')
-rw-r--r-- | contrib/libpcap/pcap-snf.c | 249 |
1 files changed, 219 insertions, 30 deletions
diff --git a/contrib/libpcap/pcap-snf.c b/contrib/libpcap/pcap-snf.c index b8025ba8ba89..207c495926b1 100644 --- a/contrib/libpcap/pcap-snf.c +++ b/contrib/libpcap/pcap-snf.c @@ -16,6 +16,9 @@ #include <unistd.h> #include <snf.h> +#if SNF_VERSION_API >= 0x0003 +#define SNF_HAVE_INJECT_API +#endif #include "pcap-int.h" #include "pcap-snf.h" @@ -26,6 +29,9 @@ struct pcap_snf { snf_handle_t snf_handle; /* opaque device handle */ snf_ring_t snf_ring; /* opaque device ring handle */ +#ifdef SNF_HAVE_INJECT_API + snf_inject_t snf_inj; /* inject handle, if inject is used */ +#endif int snf_timeout; int snf_boardnum; }; @@ -41,10 +47,11 @@ static int snf_pcap_stats(pcap_t *p, struct pcap_stat *ps) { struct snf_ring_stats stats; + struct pcap_snf *snfps = p->priv; int rc; - if ((rc = snf_ring_getstats(ps->snf_ring, &stats))) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_get_stats: %s", + if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_get_stats: %s", pcap_strerror(rc)); return -1; } @@ -57,12 +64,12 @@ snf_pcap_stats(pcap_t *p, struct pcap_stat *ps) static void snf_platform_cleanup(pcap_t *p) { - struct pcap_snf *ps; - - if (p == NULL) - return; - ps = p->priv; + struct pcap_snf *ps = p->priv; +#ifdef SNF_HAVE_INJECT_API + if (ps->snf_inj) + snf_inject_close(ps->snf_inj); +#endif snf_ring_close(ps->snf_ring); snf_close(ps->snf_handle); pcap_cleanup_live_common(p); @@ -96,14 +103,23 @@ snf_setnonblock(pcap_t *p, int nonblock, char *errbuf) static inline struct timeval -snf_timestamp_to_timeval(const int64_t ts_nanosec) +snf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision) { struct timeval tv; - int32_t rem; + long tv_nsec; + if (ts_nanosec == 0) return (struct timeval) { 0, 0 }; + tv.tv_sec = ts_nanosec / _NSEC_PER_SEC; - tv.tv_usec = (ts_nanosec % _NSEC_PER_SEC) / 1000; + tv_nsec = (ts_nanosec % _NSEC_PER_SEC); + + /* libpcap expects tv_usec to be nanos if using nanosecond precision. */ + if (tstamp_precision == PCAP_TSTAMP_PRECISION_NANO) + tv.tv_usec = tv_nsec; + else + tv.tv_usec = tv_nsec / 1000; + return tv; } @@ -114,11 +130,13 @@ snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) struct pcap_pkthdr hdr; int i, flags, err, caplen, n; struct snf_recv_req req; + int nonblock, timeout; - if (!p || cnt == 0) + if (!p) return -1; n = 0; + timeout = ps->snf_timeout; while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) { /* * Has "pcap_breakloop()" been called? @@ -132,15 +150,18 @@ snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) } } - err = snf_ring_recv(ps->snf_ring, ps->snf_timeout, &req); + err = snf_ring_recv(ps->snf_ring, timeout, &req); if (err) { - if (err == EBUSY || err == EAGAIN) - return (0); - if (err == EINTR) + if (err == EBUSY || err == EAGAIN) { + return (n); + } + else if (err == EINTR) { + timeout = 0; continue; - if (err != 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_read: %s", + } + else { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_read: %s", pcap_strerror(err)); return -1; } @@ -152,12 +173,17 @@ snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) { - hdr.ts = snf_timestamp_to_timeval(req.timestamp); + hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision); hdr.caplen = caplen; hdr.len = req.length; callback(user, &hdr, req.pkt_addr); } n++; + + /* After one successful packet is received, we won't block + * again for that timeout. */ + if (timeout != 0) + timeout = 0; } return (n); } @@ -184,30 +210,55 @@ snf_setfilter(pcap_t *p, struct bpf_program *fp) static int snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_) { - strlcpy(p->errbuf, "Sending packets isn't supported with snf", +#ifdef SNF_HAVE_INJECT_API + struct pcap_snf *ps = p->priv; + int rc; + if (ps->snf_inj == NULL) { + rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj); + if (rc) { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snf_inject_open: %s", pcap_strerror(rc)); + return (-1); + } + } + + rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size); + if (!rc) { + return (size); + } + else { + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_inject_send: %s", + pcap_strerror(rc)); + return (-1); + } +#else + strlcpy(p->errbuf, "Sending packets isn't supported with this snf version", PCAP_ERRBUF_SIZE); return (-1); +#endif } static int snf_activate(pcap_t* p) { struct pcap_snf *ps = p->priv; - char *device = p->opt.source; + char *device = p->opt.device; const char *nr = NULL; int err; - int flags = 0; + int flags = -1, ring_id = -1; if (device == NULL) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno)); return -1; } /* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1. * Since libpcap isn't thread-safe */ - if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) - flags |= SNF_F_PSHARED; + if ((nr = getenv("SNF_FLAGS")) && *nr) + flags = strtol(nr, NULL, 0); + else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1) + flags = SNF_F_PSHARED; else nr = NULL; @@ -218,15 +269,19 @@ snf_activate(pcap_t* p) flags, /* may want pshared */ &ps->snf_handle); if (err != 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_open failed: %s", pcap_strerror(err)); return -1; } - err = snf_ring_open(ps->snf_handle, &ps->snf_ring); + if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) { + ring_id = (int) strtol(nr, NULL, 0); + } + err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring); if (err != 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, - "snf_ring_open failed: %s", pcap_strerror(err)); + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + "snf_ring_open_id(ring=%d) failed: %s", + ring_id, pcap_strerror(err)); return -1; } @@ -237,7 +292,7 @@ snf_activate(pcap_t* p) err = snf_start(ps->snf_handle); if (err != 0) { - snprintf(p->errbuf, PCAP_ERRBUF_SIZE, + pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_start failed: %s", pcap_strerror(err)); return -1; } @@ -256,12 +311,104 @@ snf_activate(pcap_t* p) p->setnonblock_op = snf_setnonblock; p->stats_op = snf_pcap_stats; p->cleanup_op = snf_platform_cleanup; +#ifdef SNF_HAVE_INJECT_API + ps->snf_inj = NULL; +#endif return 0; } +#define MAX_DESC_LENGTH 128 int snf_findalldevs(pcap_if_t **devlistp, char *errbuf) { + pcap_if_t *devlist = NULL,*curdev,*prevdev; + pcap_addr_t *curaddr; + struct snf_ifaddrs *ifaddrs, *ifa; + char desc[MAX_DESC_LENGTH]; + int ret; + + if (snf_init(SNF_VERSION_API)) + return (-1); + + if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) + { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_getifaddrs: %s", pcap_strerror(errno)); + return (-1); + } + ifa = ifaddrs; + while (ifa) + { + /* + * Allocate a new entry + */ + curdev = (pcap_if_t *)malloc(sizeof(pcap_if_t)); + if (curdev == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_findalldevs malloc: %s", pcap_strerror(errno)); + return (-1); + } + if (devlist == NULL) /* save first entry */ + devlist = curdev; + else + prevdev->next = curdev; + /* + * Fill in the entry. + */ + curdev->next = NULL; + curdev->name = strdup(ifa->snf_ifa_name); + if (curdev->name == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_findalldevs strdup: %s", pcap_strerror(errno)); + free(curdev); + return (-1); + } + (void)pcap_snprintf(desc,MAX_DESC_LENGTH,"Myricom snf%d", + ifa->snf_ifa_portnum); + curdev->description = strdup(desc); + if (curdev->description == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_findalldevs strdup1: %s", pcap_strerror(errno)); + free(curdev->name); + free(curdev); + return (-1); + } + curdev->addresses = NULL; + curdev->flags = 0; + + curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t)); + if (curaddr == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_findalldevs malloc1: %s", pcap_strerror(errno)); + free(curdev->description); + free(curdev->name); + free(curdev); + return (-1); + } + curdev->addresses = curaddr; + curaddr->next = NULL; + curaddr->addr = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage)); + if (curaddr->addr == NULL) { + (void)pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "malloc2: %s", pcap_strerror(errno)); + free(curdev->description); + free(curdev->name); + free(curaddr); + free(curdev); + return (-1); + } + curaddr->addr->sa_family = AF_INET; + curaddr->netmask = NULL; + curaddr->broadaddr = NULL; + curaddr->dstaddr = NULL; + curaddr->next = NULL; + + prevdev = curdev; + ifa = ifa->snf_ifa_next; + } + snf_freeifaddrs(ifaddrs); + *devlistp = devlist; + /* * There are no platform-specific devices since each device * exists as a regular Ethernet device. @@ -320,12 +467,54 @@ snf_create(const char *device, char *ebuf, int *is_ours) /* OK, it's probably ours. */ *is_ours = 1; - p = pcap_create_common(device, ebuf, sizeof (struct pcap_snf)); + p = pcap_create_common(ebuf, sizeof (struct pcap_snf)); if (p == NULL) return NULL; ps = p->priv; + /* + * We support microsecond and nanosecond time stamps. + */ + p->tstamp_precision_count = 2; + p->tstamp_precision_list = malloc(2 * sizeof(u_int)); + if (p->tstamp_precision_list == NULL) { + pcap_snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + pcap_close(p); + return NULL; + } + p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO; + p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO; + p->activate_op = snf_activate; ps->snf_boardnum = boardnum; return p; } + +#ifdef SNF_ONLY +/* + * This libpcap build supports only SNF cards, not regular network + * interfaces.. + */ + +/* + * There are no regular interfaces, just DAG interfaces. + */ +int +pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf) +{ + *alldevsp = NULL; + return (0); +} + +/* + * Attempts to open a regular interface fail. + */ +pcap_t * +pcap_create_interface(const char *device, char *errbuf) +{ + pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, + "This version of libpcap only supports SNF cards"); + return NULL; +} +#endif |