diff options
-rw-r--r-- | pcap-snf.c | 170 | ||||
-rw-r--r-- | pcap.c | 3 |
2 files changed, 158 insertions, 15 deletions
@@ -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,9 +47,10 @@ 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))) { + if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_get_stats: %s", pcap_strerror(rc)); return -1; @@ -62,6 +69,10 @@ snf_platform_cleanup(pcap_t *p) if (p == NULL) return; +#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); @@ -113,12 +124,14 @@ 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; - while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) { + timeout = ps->snf_timeout; + while (n < cnt || cnt <= 0) { /* * Has "pcap_breakloop()" been called? */ @@ -131,14 +144,17 @@ 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 == EAGAIN) { + return (n); + } + else if (err == EINTR) { + timeout = 0; continue; - if (err != 0) { + } + else { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_read: %s", pcap_strerror(err)); return -1; @@ -157,6 +173,11 @@ snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) 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); } @@ -183,9 +204,32 @@ 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) { + 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 { + 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 @@ -195,7 +239,7 @@ snf_activate(pcap_t* p) char *device = p->opt.source; const char *nr = NULL; int err; - int flags = 0; + int flags = -1, ring_id = -1; if (device == NULL) { snprintf(p->errbuf, PCAP_ERRBUF_SIZE, @@ -205,8 +249,10 @@ snf_activate(pcap_t* p) /* 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; @@ -222,10 +268,14 @@ snf_activate(pcap_t* p) 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)); + "snf_ring_open_id(ring=%d) failed: %s", + ring_id, pcap_strerror(err)); return -1; } @@ -255,12 +305,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)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)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)snprintf(errbuf, PCAP_ERRBUF_SIZE, + "snf_findalldevs strdup: %s", pcap_strerror(errno)); + free(curdev); + return (-1); + } + (void)snprintf(desc,MAX_DESC_LENGTH,"Myricom snf%d", + ifa->snf_ifa_portnum); + curdev->description = strdup(desc); + if (curdev->description == NULL) { + (void)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)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)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. @@ -304,7 +304,8 @@ pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) pcap_t * pcap_create(const char *source, char *errbuf) { - return (snf_create(source, errbuf)); + int is_ours; + return (snf_create(source, errbuf, &is_ours)); } #else /* regular pcap */ struct capture_source_type { |