xref: /minix3/external/bsd/libpcap/dist/pcap-snf.c (revision d56f51ea7d8b9045e5c8e2028422523d3f9a5840)
1*d56f51eaSDavid van Moolenbroek #include <sys/cdefs.h>
2*d56f51eaSDavid van Moolenbroek __RCSID("$NetBSD: pcap-snf.c,v 1.3 2015/03/31 21:39:42 christos Exp $");
3*d56f51eaSDavid van Moolenbroek 
4*d56f51eaSDavid van Moolenbroek /*	$NetBSD: pcap-snf.c,v 1.3 2015/03/31 21:39:42 christos Exp $	*/
5*d56f51eaSDavid van Moolenbroek 
6*d56f51eaSDavid van Moolenbroek #ifdef HAVE_CONFIG_H
7*d56f51eaSDavid van Moolenbroek #include "config.h"
8*d56f51eaSDavid van Moolenbroek #endif
9*d56f51eaSDavid van Moolenbroek 
10*d56f51eaSDavid van Moolenbroek #include <sys/param.h>
11*d56f51eaSDavid van Moolenbroek 
12*d56f51eaSDavid van Moolenbroek #include <stdlib.h>
13*d56f51eaSDavid van Moolenbroek #include <string.h>
14*d56f51eaSDavid van Moolenbroek #include <errno.h>
15*d56f51eaSDavid van Moolenbroek 
16*d56f51eaSDavid van Moolenbroek #include <ctype.h>
17*d56f51eaSDavid van Moolenbroek #include <netinet/in.h>
18*d56f51eaSDavid van Moolenbroek #include <sys/mman.h>
19*d56f51eaSDavid van Moolenbroek #include <sys/socket.h>
20*d56f51eaSDavid van Moolenbroek #include <sys/types.h>
21*d56f51eaSDavid van Moolenbroek #include <unistd.h>
22*d56f51eaSDavid van Moolenbroek 
23*d56f51eaSDavid van Moolenbroek #include <snf.h>
24*d56f51eaSDavid van Moolenbroek #if SNF_VERSION_API >= 0x0003
25*d56f51eaSDavid van Moolenbroek #define SNF_HAVE_INJECT_API
26*d56f51eaSDavid van Moolenbroek #endif
27*d56f51eaSDavid van Moolenbroek 
28*d56f51eaSDavid van Moolenbroek #include "pcap-int.h"
29*d56f51eaSDavid van Moolenbroek #include "pcap-snf.h"
30*d56f51eaSDavid van Moolenbroek 
31*d56f51eaSDavid van Moolenbroek /*
32*d56f51eaSDavid van Moolenbroek  * Private data for capturing on SNF devices.
33*d56f51eaSDavid van Moolenbroek  */
34*d56f51eaSDavid van Moolenbroek struct pcap_snf {
35*d56f51eaSDavid van Moolenbroek 	snf_handle_t snf_handle; /* opaque device handle */
36*d56f51eaSDavid van Moolenbroek 	snf_ring_t   snf_ring;   /* opaque device ring handle */
37*d56f51eaSDavid van Moolenbroek #ifdef SNF_HAVE_INJECT_API
38*d56f51eaSDavid van Moolenbroek         snf_inject_t snf_inj;    /* inject handle, if inject is used */
39*d56f51eaSDavid van Moolenbroek #endif
40*d56f51eaSDavid van Moolenbroek         int          snf_timeout;
41*d56f51eaSDavid van Moolenbroek         int          snf_boardnum;
42*d56f51eaSDavid van Moolenbroek };
43*d56f51eaSDavid van Moolenbroek 
44*d56f51eaSDavid van Moolenbroek static int
snf_set_datalink(pcap_t * p,int dlt)45*d56f51eaSDavid van Moolenbroek snf_set_datalink(pcap_t *p, int dlt)
46*d56f51eaSDavid van Moolenbroek {
47*d56f51eaSDavid van Moolenbroek 	p->linktype = dlt;
48*d56f51eaSDavid van Moolenbroek 	return (0);
49*d56f51eaSDavid van Moolenbroek }
50*d56f51eaSDavid van Moolenbroek 
51*d56f51eaSDavid van Moolenbroek static int
snf_pcap_stats(pcap_t * p,struct pcap_stat * ps)52*d56f51eaSDavid van Moolenbroek snf_pcap_stats(pcap_t *p, struct pcap_stat *ps)
53*d56f51eaSDavid van Moolenbroek {
54*d56f51eaSDavid van Moolenbroek 	struct snf_ring_stats stats;
55*d56f51eaSDavid van Moolenbroek 	struct pcap_snf *snfps = p->priv;
56*d56f51eaSDavid van Moolenbroek 	int rc;
57*d56f51eaSDavid van Moolenbroek 
58*d56f51eaSDavid van Moolenbroek 	if ((rc = snf_ring_getstats(snfps->snf_ring, &stats))) {
59*d56f51eaSDavid van Moolenbroek 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_get_stats: %s",
60*d56f51eaSDavid van Moolenbroek 			 pcap_strerror(rc));
61*d56f51eaSDavid van Moolenbroek 		return -1;
62*d56f51eaSDavid van Moolenbroek 	}
63*d56f51eaSDavid van Moolenbroek 	ps->ps_recv = stats.ring_pkt_recv + stats.ring_pkt_overflow;
64*d56f51eaSDavid van Moolenbroek 	ps->ps_drop = stats.ring_pkt_overflow;
65*d56f51eaSDavid van Moolenbroek 	ps->ps_ifdrop = stats.nic_pkt_overflow + stats.nic_pkt_bad;
66*d56f51eaSDavid van Moolenbroek 	return 0;
67*d56f51eaSDavid van Moolenbroek }
68*d56f51eaSDavid van Moolenbroek 
69*d56f51eaSDavid van Moolenbroek static void
snf_platform_cleanup(pcap_t * p)70*d56f51eaSDavid van Moolenbroek snf_platform_cleanup(pcap_t *p)
71*d56f51eaSDavid van Moolenbroek {
72*d56f51eaSDavid van Moolenbroek 	struct pcap_snf *ps = p->priv;
73*d56f51eaSDavid van Moolenbroek 
74*d56f51eaSDavid van Moolenbroek 	if (p == NULL)
75*d56f51eaSDavid van Moolenbroek 		return;
76*d56f51eaSDavid van Moolenbroek 
77*d56f51eaSDavid van Moolenbroek #ifdef SNF_HAVE_INJECT_API
78*d56f51eaSDavid van Moolenbroek         if (ps->snf_inj)
79*d56f51eaSDavid van Moolenbroek                 snf_inject_close(ps->snf_inj);
80*d56f51eaSDavid van Moolenbroek #endif
81*d56f51eaSDavid van Moolenbroek 	snf_ring_close(ps->snf_ring);
82*d56f51eaSDavid van Moolenbroek 	snf_close(ps->snf_handle);
83*d56f51eaSDavid van Moolenbroek 	pcap_cleanup_live_common(p);
84*d56f51eaSDavid van Moolenbroek }
85*d56f51eaSDavid van Moolenbroek 
86*d56f51eaSDavid van Moolenbroek static int
snf_getnonblock(pcap_t * p,char * errbuf)87*d56f51eaSDavid van Moolenbroek snf_getnonblock(pcap_t *p, char *errbuf)
88*d56f51eaSDavid van Moolenbroek {
89*d56f51eaSDavid van Moolenbroek 	struct pcap_snf *ps = p->priv;
90*d56f51eaSDavid van Moolenbroek 
91*d56f51eaSDavid van Moolenbroek 	return (ps->snf_timeout == 0);
92*d56f51eaSDavid van Moolenbroek }
93*d56f51eaSDavid van Moolenbroek 
94*d56f51eaSDavid van Moolenbroek static int
snf_setnonblock(pcap_t * p,int nonblock,char * errbuf)95*d56f51eaSDavid van Moolenbroek snf_setnonblock(pcap_t *p, int nonblock, char *errbuf)
96*d56f51eaSDavid van Moolenbroek {
97*d56f51eaSDavid van Moolenbroek 	struct pcap_snf *ps = p->priv;
98*d56f51eaSDavid van Moolenbroek 
99*d56f51eaSDavid van Moolenbroek 	if (nonblock)
100*d56f51eaSDavid van Moolenbroek 		ps->snf_timeout = 0;
101*d56f51eaSDavid van Moolenbroek 	else {
102*d56f51eaSDavid van Moolenbroek 		if (p->opt.timeout <= 0)
103*d56f51eaSDavid van Moolenbroek 			ps->snf_timeout = -1; /* forever */
104*d56f51eaSDavid van Moolenbroek 		else
105*d56f51eaSDavid van Moolenbroek 			ps->snf_timeout = p->opt.timeout;
106*d56f51eaSDavid van Moolenbroek 	}
107*d56f51eaSDavid van Moolenbroek 	return (0);
108*d56f51eaSDavid van Moolenbroek }
109*d56f51eaSDavid van Moolenbroek 
110*d56f51eaSDavid van Moolenbroek #define _NSEC_PER_SEC 1000000000
111*d56f51eaSDavid van Moolenbroek 
112*d56f51eaSDavid van Moolenbroek static inline
113*d56f51eaSDavid van Moolenbroek struct timeval
snf_timestamp_to_timeval(const int64_t ts_nanosec,const int tstamp_precision)114*d56f51eaSDavid van Moolenbroek snf_timestamp_to_timeval(const int64_t ts_nanosec, const int tstamp_precision)
115*d56f51eaSDavid van Moolenbroek {
116*d56f51eaSDavid van Moolenbroek 	struct timeval tv;
117*d56f51eaSDavid van Moolenbroek 	long tv_nsec;
118*d56f51eaSDavid van Moolenbroek 
119*d56f51eaSDavid van Moolenbroek 	if (ts_nanosec == 0)
120*d56f51eaSDavid van Moolenbroek 		return (struct timeval) { 0, 0 };
121*d56f51eaSDavid van Moolenbroek 
122*d56f51eaSDavid van Moolenbroek 	tv.tv_sec = ts_nanosec / _NSEC_PER_SEC;
123*d56f51eaSDavid van Moolenbroek 	tv_nsec = (ts_nanosec % _NSEC_PER_SEC);
124*d56f51eaSDavid van Moolenbroek 
125*d56f51eaSDavid van Moolenbroek 	/* libpcap expects tv_usec to be nanos if using nanosecond precision. */
126*d56f51eaSDavid van Moolenbroek 	if (tstamp_precision == PCAP_TSTAMP_PRECISION_NANO)
127*d56f51eaSDavid van Moolenbroek 		tv.tv_usec = tv_nsec;
128*d56f51eaSDavid van Moolenbroek 	else
129*d56f51eaSDavid van Moolenbroek 		tv.tv_usec = tv_nsec / 1000;
130*d56f51eaSDavid van Moolenbroek 
131*d56f51eaSDavid van Moolenbroek 	return tv;
132*d56f51eaSDavid van Moolenbroek }
133*d56f51eaSDavid van Moolenbroek 
134*d56f51eaSDavid van Moolenbroek static int
snf_read(pcap_t * p,int cnt,pcap_handler callback,u_char * user)135*d56f51eaSDavid van Moolenbroek snf_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
136*d56f51eaSDavid van Moolenbroek {
137*d56f51eaSDavid van Moolenbroek 	struct pcap_snf *ps = p->priv;
138*d56f51eaSDavid van Moolenbroek 	struct pcap_pkthdr hdr;
139*d56f51eaSDavid van Moolenbroek 	int i, flags, err, caplen, n;
140*d56f51eaSDavid van Moolenbroek 	struct snf_recv_req req;
141*d56f51eaSDavid van Moolenbroek 	int nonblock, timeout;
142*d56f51eaSDavid van Moolenbroek 
143*d56f51eaSDavid van Moolenbroek 	if (!p)
144*d56f51eaSDavid van Moolenbroek 		return -1;
145*d56f51eaSDavid van Moolenbroek 
146*d56f51eaSDavid van Moolenbroek 	n = 0;
147*d56f51eaSDavid van Moolenbroek 	timeout = ps->snf_timeout;
148*d56f51eaSDavid van Moolenbroek 	while (n < cnt || PACKET_COUNT_IS_UNLIMITED(cnt)) {
149*d56f51eaSDavid van Moolenbroek 		/*
150*d56f51eaSDavid van Moolenbroek 		 * Has "pcap_breakloop()" been called?
151*d56f51eaSDavid van Moolenbroek 		 */
152*d56f51eaSDavid van Moolenbroek 		if (p->break_loop) {
153*d56f51eaSDavid van Moolenbroek 			if (n == 0) {
154*d56f51eaSDavid van Moolenbroek 				p->break_loop = 0;
155*d56f51eaSDavid van Moolenbroek 				return (-2);
156*d56f51eaSDavid van Moolenbroek 			} else {
157*d56f51eaSDavid van Moolenbroek 				return (n);
158*d56f51eaSDavid van Moolenbroek 			}
159*d56f51eaSDavid van Moolenbroek 		}
160*d56f51eaSDavid van Moolenbroek 
161*d56f51eaSDavid van Moolenbroek 		err = snf_ring_recv(ps->snf_ring, timeout, &req);
162*d56f51eaSDavid van Moolenbroek 
163*d56f51eaSDavid van Moolenbroek 		if (err) {
164*d56f51eaSDavid van Moolenbroek 			if (err == EBUSY || err == EAGAIN) {
165*d56f51eaSDavid van Moolenbroek 				return (n);
166*d56f51eaSDavid van Moolenbroek 			}
167*d56f51eaSDavid van Moolenbroek 			else if (err == EINTR) {
168*d56f51eaSDavid van Moolenbroek 				timeout = 0;
169*d56f51eaSDavid van Moolenbroek 				continue;
170*d56f51eaSDavid van Moolenbroek 			}
171*d56f51eaSDavid van Moolenbroek 			else {
172*d56f51eaSDavid van Moolenbroek 				snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_read: %s",
173*d56f51eaSDavid van Moolenbroek 				 	 pcap_strerror(err));
174*d56f51eaSDavid van Moolenbroek 				return -1;
175*d56f51eaSDavid van Moolenbroek 			}
176*d56f51eaSDavid van Moolenbroek 		}
177*d56f51eaSDavid van Moolenbroek 
178*d56f51eaSDavid van Moolenbroek 		caplen = req.length;
179*d56f51eaSDavid van Moolenbroek 		if (caplen > p->snapshot)
180*d56f51eaSDavid van Moolenbroek 			caplen = p->snapshot;
181*d56f51eaSDavid van Moolenbroek 
182*d56f51eaSDavid van Moolenbroek 		if ((p->fcode.bf_insns == NULL) ||
183*d56f51eaSDavid van Moolenbroek 		     bpf_filter(p->fcode.bf_insns, req.pkt_addr, req.length, caplen)) {
184*d56f51eaSDavid van Moolenbroek 			hdr.ts = snf_timestamp_to_timeval(req.timestamp, p->opt.tstamp_precision);
185*d56f51eaSDavid van Moolenbroek 			hdr.caplen = caplen;
186*d56f51eaSDavid van Moolenbroek 			hdr.len = req.length;
187*d56f51eaSDavid van Moolenbroek 			callback(user, &hdr, req.pkt_addr);
188*d56f51eaSDavid van Moolenbroek 		}
189*d56f51eaSDavid van Moolenbroek 		n++;
190*d56f51eaSDavid van Moolenbroek 
191*d56f51eaSDavid van Moolenbroek 		/* After one successful packet is received, we won't block
192*d56f51eaSDavid van Moolenbroek 		* again for that timeout. */
193*d56f51eaSDavid van Moolenbroek 		if (timeout != 0)
194*d56f51eaSDavid van Moolenbroek 			timeout = 0;
195*d56f51eaSDavid van Moolenbroek 	}
196*d56f51eaSDavid van Moolenbroek 	return (n);
197*d56f51eaSDavid van Moolenbroek }
198*d56f51eaSDavid van Moolenbroek 
199*d56f51eaSDavid van Moolenbroek static int
snf_setfilter(pcap_t * p,struct bpf_program * fp)200*d56f51eaSDavid van Moolenbroek snf_setfilter(pcap_t *p, struct bpf_program *fp)
201*d56f51eaSDavid van Moolenbroek {
202*d56f51eaSDavid van Moolenbroek 	if (!p)
203*d56f51eaSDavid van Moolenbroek 		return -1;
204*d56f51eaSDavid van Moolenbroek 	if (!fp) {
205*d56f51eaSDavid van Moolenbroek 		strncpy(p->errbuf, "setfilter: No filter specified",
206*d56f51eaSDavid van Moolenbroek 			sizeof(p->errbuf));
207*d56f51eaSDavid van Moolenbroek 		return -1;
208*d56f51eaSDavid van Moolenbroek 	}
209*d56f51eaSDavid van Moolenbroek 
210*d56f51eaSDavid van Moolenbroek 	/* Make our private copy of the filter */
211*d56f51eaSDavid van Moolenbroek 
212*d56f51eaSDavid van Moolenbroek 	if (install_bpf_program(p, fp) < 0)
213*d56f51eaSDavid van Moolenbroek 		return -1;
214*d56f51eaSDavid van Moolenbroek 
215*d56f51eaSDavid van Moolenbroek 	return (0);
216*d56f51eaSDavid van Moolenbroek }
217*d56f51eaSDavid van Moolenbroek 
218*d56f51eaSDavid van Moolenbroek static int
snf_inject(pcap_t * p,const void * buf _U_,size_t size _U_)219*d56f51eaSDavid van Moolenbroek snf_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
220*d56f51eaSDavid van Moolenbroek {
221*d56f51eaSDavid van Moolenbroek #ifdef SNF_HAVE_INJECT_API
222*d56f51eaSDavid van Moolenbroek 	struct pcap_snf *ps = p->priv;
223*d56f51eaSDavid van Moolenbroek         int rc;
224*d56f51eaSDavid van Moolenbroek         if (ps->snf_inj == NULL) {
225*d56f51eaSDavid van Moolenbroek                 rc = snf_inject_open(ps->snf_boardnum, 0, &ps->snf_inj);
226*d56f51eaSDavid van Moolenbroek                 if (rc) {
227*d56f51eaSDavid van Moolenbroek                         snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
228*d56f51eaSDavid van Moolenbroek                                 "snf_inject_open: %s", pcap_strerror(rc));
229*d56f51eaSDavid van Moolenbroek                         return (-1);
230*d56f51eaSDavid van Moolenbroek                 }
231*d56f51eaSDavid van Moolenbroek         }
232*d56f51eaSDavid van Moolenbroek 
233*d56f51eaSDavid van Moolenbroek         rc = snf_inject_send(ps->snf_inj, -1, 0, buf, size);
234*d56f51eaSDavid van Moolenbroek         if (!rc) {
235*d56f51eaSDavid van Moolenbroek                 return (size);
236*d56f51eaSDavid van Moolenbroek         }
237*d56f51eaSDavid van Moolenbroek         else {
238*d56f51eaSDavid van Moolenbroek                 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "snf_inject_send: %s",
239*d56f51eaSDavid van Moolenbroek                          pcap_strerror(rc));
240*d56f51eaSDavid van Moolenbroek                 return (-1);
241*d56f51eaSDavid van Moolenbroek         }
242*d56f51eaSDavid van Moolenbroek #else
243*d56f51eaSDavid van Moolenbroek 	strlcpy(p->errbuf, "Sending packets isn't supported with this snf version",
244*d56f51eaSDavid van Moolenbroek 	    PCAP_ERRBUF_SIZE);
245*d56f51eaSDavid van Moolenbroek 	return (-1);
246*d56f51eaSDavid van Moolenbroek #endif
247*d56f51eaSDavid van Moolenbroek }
248*d56f51eaSDavid van Moolenbroek 
249*d56f51eaSDavid van Moolenbroek static int
snf_activate(pcap_t * p)250*d56f51eaSDavid van Moolenbroek snf_activate(pcap_t* p)
251*d56f51eaSDavid van Moolenbroek {
252*d56f51eaSDavid van Moolenbroek 	struct pcap_snf *ps = p->priv;
253*d56f51eaSDavid van Moolenbroek 	char *device = p->opt.source;
254*d56f51eaSDavid van Moolenbroek 	const char *nr = NULL;
255*d56f51eaSDavid van Moolenbroek 	int err;
256*d56f51eaSDavid van Moolenbroek 	int flags = -1, ring_id = -1;
257*d56f51eaSDavid van Moolenbroek 
258*d56f51eaSDavid van Moolenbroek 	if (device == NULL) {
259*d56f51eaSDavid van Moolenbroek 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
260*d56f51eaSDavid van Moolenbroek 			 "device is NULL: %s", pcap_strerror(errno));
261*d56f51eaSDavid van Moolenbroek 		return -1;
262*d56f51eaSDavid van Moolenbroek 	}
263*d56f51eaSDavid van Moolenbroek 
264*d56f51eaSDavid van Moolenbroek 	/* In Libpcap, we set pshared by default if NUM_RINGS is set to > 1.
265*d56f51eaSDavid van Moolenbroek 	 * Since libpcap isn't thread-safe */
266*d56f51eaSDavid van Moolenbroek 	if ((nr = getenv("SNF_FLAGS")) && *nr)
267*d56f51eaSDavid van Moolenbroek 		flags = strtol(nr, NULL, 0);
268*d56f51eaSDavid van Moolenbroek 	else if ((nr = getenv("SNF_NUM_RINGS")) && *nr && atoi(nr) > 1)
269*d56f51eaSDavid van Moolenbroek 		flags = SNF_F_PSHARED;
270*d56f51eaSDavid van Moolenbroek 	else
271*d56f51eaSDavid van Moolenbroek 		nr = NULL;
272*d56f51eaSDavid van Moolenbroek 
273*d56f51eaSDavid van Moolenbroek 	err = snf_open(ps->snf_boardnum,
274*d56f51eaSDavid van Moolenbroek 			0, /* let SNF API parse SNF_NUM_RINGS, if set */
275*d56f51eaSDavid van Moolenbroek 			NULL, /* default RSS, or use SNF_RSS_FLAGS env */
276*d56f51eaSDavid van Moolenbroek 			0, /* default to SNF_DATARING_SIZE from env */
277*d56f51eaSDavid van Moolenbroek 			flags, /* may want pshared */
278*d56f51eaSDavid van Moolenbroek 			&ps->snf_handle);
279*d56f51eaSDavid van Moolenbroek 	if (err != 0) {
280*d56f51eaSDavid van Moolenbroek 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
281*d56f51eaSDavid van Moolenbroek 			 "snf_open failed: %s", pcap_strerror(err));
282*d56f51eaSDavid van Moolenbroek 		return -1;
283*d56f51eaSDavid van Moolenbroek 	}
284*d56f51eaSDavid van Moolenbroek 
285*d56f51eaSDavid van Moolenbroek 	if ((nr = getenv("SNF_PCAP_RING_ID")) && *nr) {
286*d56f51eaSDavid van Moolenbroek 		ring_id = (int) strtol(nr, NULL, 0);
287*d56f51eaSDavid van Moolenbroek 	}
288*d56f51eaSDavid van Moolenbroek 	err = snf_ring_open_id(ps->snf_handle, ring_id, &ps->snf_ring);
289*d56f51eaSDavid van Moolenbroek 	if (err != 0) {
290*d56f51eaSDavid van Moolenbroek 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
291*d56f51eaSDavid van Moolenbroek 			 "snf_ring_open_id(ring=%d) failed: %s",
292*d56f51eaSDavid van Moolenbroek 			 ring_id, pcap_strerror(err));
293*d56f51eaSDavid van Moolenbroek 		return -1;
294*d56f51eaSDavid van Moolenbroek 	}
295*d56f51eaSDavid van Moolenbroek 
296*d56f51eaSDavid van Moolenbroek 	if (p->opt.timeout <= 0)
297*d56f51eaSDavid van Moolenbroek 		ps->snf_timeout = -1;
298*d56f51eaSDavid van Moolenbroek 	else
299*d56f51eaSDavid van Moolenbroek 		ps->snf_timeout = p->opt.timeout;
300*d56f51eaSDavid van Moolenbroek 
301*d56f51eaSDavid van Moolenbroek 	err = snf_start(ps->snf_handle);
302*d56f51eaSDavid van Moolenbroek 	if (err != 0) {
303*d56f51eaSDavid van Moolenbroek 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
304*d56f51eaSDavid van Moolenbroek 			 "snf_start failed: %s", pcap_strerror(err));
305*d56f51eaSDavid van Moolenbroek 		return -1;
306*d56f51eaSDavid van Moolenbroek 	}
307*d56f51eaSDavid van Moolenbroek 
308*d56f51eaSDavid van Moolenbroek 	/*
309*d56f51eaSDavid van Moolenbroek 	 * "select()" and "poll()" don't work on snf descriptors.
310*d56f51eaSDavid van Moolenbroek 	 */
311*d56f51eaSDavid van Moolenbroek 	p->selectable_fd = -1;
312*d56f51eaSDavid van Moolenbroek 	p->linktype = DLT_EN10MB;
313*d56f51eaSDavid van Moolenbroek 	p->read_op = snf_read;
314*d56f51eaSDavid van Moolenbroek 	p->inject_op = snf_inject;
315*d56f51eaSDavid van Moolenbroek 	p->setfilter_op = snf_setfilter;
316*d56f51eaSDavid van Moolenbroek 	p->setdirection_op = NULL; /* Not implemented.*/
317*d56f51eaSDavid van Moolenbroek 	p->set_datalink_op = snf_set_datalink;
318*d56f51eaSDavid van Moolenbroek 	p->getnonblock_op = snf_getnonblock;
319*d56f51eaSDavid van Moolenbroek 	p->setnonblock_op = snf_setnonblock;
320*d56f51eaSDavid van Moolenbroek 	p->stats_op = snf_pcap_stats;
321*d56f51eaSDavid van Moolenbroek 	p->cleanup_op = snf_platform_cleanup;
322*d56f51eaSDavid van Moolenbroek #ifdef SNF_HAVE_INJECT_API
323*d56f51eaSDavid van Moolenbroek         ps->snf_inj = NULL;
324*d56f51eaSDavid van Moolenbroek #endif
325*d56f51eaSDavid van Moolenbroek 	return 0;
326*d56f51eaSDavid van Moolenbroek }
327*d56f51eaSDavid van Moolenbroek 
328*d56f51eaSDavid van Moolenbroek #define MAX_DESC_LENGTH 128
329*d56f51eaSDavid van Moolenbroek int
snf_findalldevs(pcap_if_t ** devlistp,char * errbuf)330*d56f51eaSDavid van Moolenbroek snf_findalldevs(pcap_if_t **devlistp, char *errbuf)
331*d56f51eaSDavid van Moolenbroek {
332*d56f51eaSDavid van Moolenbroek 	pcap_if_t *devlist = NULL,*curdev,*prevdev;
333*d56f51eaSDavid van Moolenbroek 	pcap_addr_t *curaddr;
334*d56f51eaSDavid van Moolenbroek 	struct snf_ifaddrs *ifaddrs, *ifa;
335*d56f51eaSDavid van Moolenbroek 	char desc[MAX_DESC_LENGTH];
336*d56f51eaSDavid van Moolenbroek 	int ret;
337*d56f51eaSDavid van Moolenbroek 
338*d56f51eaSDavid van Moolenbroek 	if (snf_init(SNF_VERSION_API))
339*d56f51eaSDavid van Moolenbroek 		return (-1);
340*d56f51eaSDavid van Moolenbroek 
341*d56f51eaSDavid van Moolenbroek 	if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL)
342*d56f51eaSDavid van Moolenbroek 	{
343*d56f51eaSDavid van Moolenbroek 		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
344*d56f51eaSDavid van Moolenbroek 			"snf_getifaddrs: %s", pcap_strerror(errno));
345*d56f51eaSDavid van Moolenbroek 		return (-1);
346*d56f51eaSDavid van Moolenbroek 	}
347*d56f51eaSDavid van Moolenbroek 	ifa = ifaddrs;
348*d56f51eaSDavid van Moolenbroek 	while (ifa)
349*d56f51eaSDavid van Moolenbroek 	{
350*d56f51eaSDavid van Moolenbroek 		/*
351*d56f51eaSDavid van Moolenbroek 		 * Allocate a new entry
352*d56f51eaSDavid van Moolenbroek 		 */
353*d56f51eaSDavid van Moolenbroek 		curdev = (pcap_if_t *)malloc(sizeof(pcap_if_t));
354*d56f51eaSDavid van Moolenbroek 		if (curdev == NULL) {
355*d56f51eaSDavid van Moolenbroek 		(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
356*d56f51eaSDavid van Moolenbroek 			"snf_findalldevs malloc: %s", pcap_strerror(errno));
357*d56f51eaSDavid van Moolenbroek 			return (-1);
358*d56f51eaSDavid van Moolenbroek 		}
359*d56f51eaSDavid van Moolenbroek 		if (devlist == NULL) /* save first entry */
360*d56f51eaSDavid van Moolenbroek 			devlist = curdev;
361*d56f51eaSDavid van Moolenbroek 		else
362*d56f51eaSDavid van Moolenbroek 			prevdev->next = curdev;
363*d56f51eaSDavid van Moolenbroek 		/*
364*d56f51eaSDavid van Moolenbroek 		 * Fill in the entry.
365*d56f51eaSDavid van Moolenbroek 		 */
366*d56f51eaSDavid van Moolenbroek 		curdev->next = NULL;
367*d56f51eaSDavid van Moolenbroek 		curdev->name = strdup(ifa->snf_ifa_name);
368*d56f51eaSDavid van Moolenbroek 		if (curdev->name == NULL) {
369*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
370*d56f51eaSDavid van Moolenbroek 			    "snf_findalldevs strdup: %s", pcap_strerror(errno));
371*d56f51eaSDavid van Moolenbroek 			free(curdev);
372*d56f51eaSDavid van Moolenbroek 			return (-1);
373*d56f51eaSDavid van Moolenbroek 		}
374*d56f51eaSDavid van Moolenbroek 		(void)snprintf(desc,MAX_DESC_LENGTH,"Myricom snf%d",
375*d56f51eaSDavid van Moolenbroek 				ifa->snf_ifa_portnum);
376*d56f51eaSDavid van Moolenbroek 		curdev->description = strdup(desc);
377*d56f51eaSDavid van Moolenbroek 		if (curdev->description == NULL) {
378*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
379*d56f51eaSDavid van Moolenbroek 			"snf_findalldevs strdup1: %s", pcap_strerror(errno));
380*d56f51eaSDavid van Moolenbroek 			free(curdev->name);
381*d56f51eaSDavid van Moolenbroek 			free(curdev);
382*d56f51eaSDavid van Moolenbroek 			return (-1);
383*d56f51eaSDavid van Moolenbroek 		}
384*d56f51eaSDavid van Moolenbroek 		curdev->addresses = NULL;
385*d56f51eaSDavid van Moolenbroek 		curdev->flags = 0;
386*d56f51eaSDavid van Moolenbroek 
387*d56f51eaSDavid van Moolenbroek 		curaddr = (pcap_addr_t *)malloc(sizeof(pcap_addr_t));
388*d56f51eaSDavid van Moolenbroek 		if (curaddr == NULL) {
389*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
390*d56f51eaSDavid van Moolenbroek 			     "snf_findalldevs malloc1: %s", pcap_strerror(errno));
391*d56f51eaSDavid van Moolenbroek 			free(curdev->description);
392*d56f51eaSDavid van Moolenbroek 			free(curdev->name);
393*d56f51eaSDavid van Moolenbroek 			free(curdev);
394*d56f51eaSDavid van Moolenbroek 			return (-1);
395*d56f51eaSDavid van Moolenbroek 		}
396*d56f51eaSDavid van Moolenbroek 		curdev->addresses = curaddr;
397*d56f51eaSDavid van Moolenbroek 		curaddr->next = NULL;
398*d56f51eaSDavid van Moolenbroek 		curaddr->addr = (struct sockaddr*)malloc(sizeof(struct sockaddr_storage));
399*d56f51eaSDavid van Moolenbroek 		if (curaddr->addr == NULL) {
400*d56f51eaSDavid van Moolenbroek 			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
401*d56f51eaSDavid van Moolenbroek 			    "malloc2: %s", pcap_strerror(errno));
402*d56f51eaSDavid van Moolenbroek 			free(curdev->description);
403*d56f51eaSDavid van Moolenbroek 			free(curdev->name);
404*d56f51eaSDavid van Moolenbroek 			free(curaddr);
405*d56f51eaSDavid van Moolenbroek 			free(curdev);
406*d56f51eaSDavid van Moolenbroek 			return (-1);
407*d56f51eaSDavid van Moolenbroek 		}
408*d56f51eaSDavid van Moolenbroek 		curaddr->addr->sa_family = AF_INET;
409*d56f51eaSDavid van Moolenbroek 		curaddr->netmask = NULL;
410*d56f51eaSDavid van Moolenbroek 		curaddr->broadaddr = NULL;
411*d56f51eaSDavid van Moolenbroek 		curaddr->dstaddr = NULL;
412*d56f51eaSDavid van Moolenbroek 		curaddr->next = NULL;
413*d56f51eaSDavid van Moolenbroek 
414*d56f51eaSDavid van Moolenbroek 		prevdev = curdev;
415*d56f51eaSDavid van Moolenbroek 		ifa = ifa->snf_ifa_next;
416*d56f51eaSDavid van Moolenbroek 	}
417*d56f51eaSDavid van Moolenbroek 	snf_freeifaddrs(ifaddrs);
418*d56f51eaSDavid van Moolenbroek 	*devlistp = devlist;
419*d56f51eaSDavid van Moolenbroek 
420*d56f51eaSDavid van Moolenbroek 	/*
421*d56f51eaSDavid van Moolenbroek 	 * There are no platform-specific devices since each device
422*d56f51eaSDavid van Moolenbroek 	 * exists as a regular Ethernet device.
423*d56f51eaSDavid van Moolenbroek 	 */
424*d56f51eaSDavid van Moolenbroek 	return 0;
425*d56f51eaSDavid van Moolenbroek }
426*d56f51eaSDavid van Moolenbroek 
427*d56f51eaSDavid van Moolenbroek pcap_t *
snf_create(const char * device,char * ebuf,int * is_ours)428*d56f51eaSDavid van Moolenbroek snf_create(const char *device, char *ebuf, int *is_ours)
429*d56f51eaSDavid van Moolenbroek {
430*d56f51eaSDavid van Moolenbroek 	pcap_t *p;
431*d56f51eaSDavid van Moolenbroek 	int boardnum = -1;
432*d56f51eaSDavid van Moolenbroek 	struct snf_ifaddrs *ifaddrs, *ifa;
433*d56f51eaSDavid van Moolenbroek 	size_t devlen;
434*d56f51eaSDavid van Moolenbroek 	struct pcap_snf *ps;
435*d56f51eaSDavid van Moolenbroek 
436*d56f51eaSDavid van Moolenbroek 	if (snf_init(SNF_VERSION_API)) {
437*d56f51eaSDavid van Moolenbroek 		/* Can't initialize the API, so no SNF devices */
438*d56f51eaSDavid van Moolenbroek 		*is_ours = 0;
439*d56f51eaSDavid van Moolenbroek 		return NULL;
440*d56f51eaSDavid van Moolenbroek 	}
441*d56f51eaSDavid van Moolenbroek 
442*d56f51eaSDavid van Moolenbroek 	/*
443*d56f51eaSDavid van Moolenbroek 	 * Match a given interface name to our list of interface names, from
444*d56f51eaSDavid van Moolenbroek 	 * which we can obtain the intended board number
445*d56f51eaSDavid van Moolenbroek 	 */
446*d56f51eaSDavid van Moolenbroek 	if (snf_getifaddrs(&ifaddrs) || ifaddrs == NULL) {
447*d56f51eaSDavid van Moolenbroek 		/* Can't get SNF addresses */
448*d56f51eaSDavid van Moolenbroek 		*is_ours = 0;
449*d56f51eaSDavid van Moolenbroek 		return NULL;
450*d56f51eaSDavid van Moolenbroek 	}
451*d56f51eaSDavid van Moolenbroek 	devlen = strlen(device) + 1;
452*d56f51eaSDavid van Moolenbroek 	ifa = ifaddrs;
453*d56f51eaSDavid van Moolenbroek 	while (ifa) {
454*d56f51eaSDavid van Moolenbroek 		if (!strncmp(device, ifa->snf_ifa_name, devlen)) {
455*d56f51eaSDavid van Moolenbroek 			boardnum = ifa->snf_ifa_boardnum;
456*d56f51eaSDavid van Moolenbroek 			break;
457*d56f51eaSDavid van Moolenbroek 		}
458*d56f51eaSDavid van Moolenbroek 		ifa = ifa->snf_ifa_next;
459*d56f51eaSDavid van Moolenbroek 	}
460*d56f51eaSDavid van Moolenbroek 	snf_freeifaddrs(ifaddrs);
461*d56f51eaSDavid van Moolenbroek 
462*d56f51eaSDavid van Moolenbroek 	if (ifa == NULL) {
463*d56f51eaSDavid van Moolenbroek 		/*
464*d56f51eaSDavid van Moolenbroek 		 * If we can't find the device by name, support the name "snfX"
465*d56f51eaSDavid van Moolenbroek 		 * and "snf10gX" where X is the board number.
466*d56f51eaSDavid van Moolenbroek 		 */
467*d56f51eaSDavid van Moolenbroek 		if (sscanf(device, "snf10g%d", &boardnum) != 1 &&
468*d56f51eaSDavid van Moolenbroek 		    sscanf(device, "snf%d", &boardnum) != 1) {
469*d56f51eaSDavid van Moolenbroek 			/* Nope, not a supported name */
470*d56f51eaSDavid van Moolenbroek 			*is_ours = 0;
471*d56f51eaSDavid van Moolenbroek 			return NULL;
472*d56f51eaSDavid van Moolenbroek 		    }
473*d56f51eaSDavid van Moolenbroek 	}
474*d56f51eaSDavid van Moolenbroek 
475*d56f51eaSDavid van Moolenbroek 	/* OK, it's probably ours. */
476*d56f51eaSDavid van Moolenbroek 	*is_ours = 1;
477*d56f51eaSDavid van Moolenbroek 
478*d56f51eaSDavid van Moolenbroek 	p = pcap_create_common(device, ebuf, sizeof (struct pcap_snf));
479*d56f51eaSDavid van Moolenbroek 	if (p == NULL)
480*d56f51eaSDavid van Moolenbroek 		return NULL;
481*d56f51eaSDavid van Moolenbroek 	ps = p->priv;
482*d56f51eaSDavid van Moolenbroek 
483*d56f51eaSDavid van Moolenbroek 	/*
484*d56f51eaSDavid van Moolenbroek 	 * We support microsecond and nanosecond time stamps.
485*d56f51eaSDavid van Moolenbroek 	 */
486*d56f51eaSDavid van Moolenbroek 	p->tstamp_precision_count = 2;
487*d56f51eaSDavid van Moolenbroek 	p->tstamp_precision_list = malloc(2 * sizeof(u_int));
488*d56f51eaSDavid van Moolenbroek 	if (p->tstamp_precision_list == NULL) {
489*d56f51eaSDavid van Moolenbroek 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
490*d56f51eaSDavid van Moolenbroek 		    pcap_strerror(errno));
491*d56f51eaSDavid van Moolenbroek 		if (p->tstamp_type_list != NULL)
492*d56f51eaSDavid van Moolenbroek 			free(p->tstamp_type_list);
493*d56f51eaSDavid van Moolenbroek 		free(p);
494*d56f51eaSDavid van Moolenbroek 		return NULL;
495*d56f51eaSDavid van Moolenbroek 	}
496*d56f51eaSDavid van Moolenbroek 	p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
497*d56f51eaSDavid van Moolenbroek 	p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
498*d56f51eaSDavid van Moolenbroek 
499*d56f51eaSDavid van Moolenbroek 	p->activate_op = snf_activate;
500*d56f51eaSDavid van Moolenbroek 	ps->snf_boardnum = boardnum;
501*d56f51eaSDavid van Moolenbroek 	return p;
502*d56f51eaSDavid van Moolenbroek }
503