aboutsummaryrefslogtreecommitdiff
path: root/contrib/libpcap/pcap-snf.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libpcap/pcap-snf.c')
-rw-r--r--contrib/libpcap/pcap-snf.c249
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