aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pcap-snf.c170
-rw-r--r--pcap.c3
2 files changed, 158 insertions, 15 deletions
diff --git a/pcap-snf.c b/pcap-snf.c
index ee6ffa4d..5e56af8e 100644
--- a/pcap-snf.c
+++ b/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,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.
diff --git a/pcap.c b/pcap.c
index badc312b..2a75cfeb 100644
--- a/pcap.c
+++ b/pcap.c
@@ -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 {