1190214Srpaulo/*
2190214Srpaulo * This code is derived from code formerly in pcap-dlpi.c, originally
3190214Srpaulo * contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk), University College
4190214Srpaulo * London, and subsequently modified by Guy Harris (guy@alum.mit.edu),
5190214Srpaulo * Mark Pizzolato <List-tcpdump-workers@subscriptions.pizzolato.net>,
6190214Srpaulo * Mark C. Brown (mbrown@hp.com), and Sagun Shakya <Sagun.Shakya@Sun.COM>.
7190214Srpaulo */
8190214Srpaulo
9190214Srpaulo/*
10190214Srpaulo * This file contains dlpi/libdlpi related common functions used
11190214Srpaulo * by pcap-[dlpi,libdlpi].c.
12190214Srpaulo */
13190214Srpaulo
14190214Srpaulo#ifdef HAVE_CONFIG_H
15190214Srpaulo#include "config.h"
16190214Srpaulo#endif
17190214Srpaulo
18214518Srpaulo#ifndef DL_IPATM
19214518Srpaulo#define DL_IPATM	0x12	/* ATM Classical IP interface */
20214518Srpaulo#endif
21214518Srpaulo
22190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H
23190214Srpaulo	/*
24190214Srpaulo	 * Size of a bufmod chunk to pass upstream; that appears to be the
25190214Srpaulo	 * biggest value to which you can set it, and setting it to that value
26190214Srpaulo	 * (which is bigger than what appears to be the Solaris default of 8192)
27190214Srpaulo	 * reduces the number of packet drops.
28190214Srpaulo	 */
29190214Srpaulo#define	CHUNKSIZE	65536
30190214Srpaulo
31190214Srpaulo	/*
32190214Srpaulo	 * Size of the buffer to allocate for packet data we read; it must be
33190214Srpaulo	 * large enough to hold a chunk.
34190214Srpaulo	 */
35190214Srpaulo#define	PKTBUFSIZE	CHUNKSIZE
36190214Srpaulo
37190214Srpaulo#else /* HAVE_SYS_BUFMOD_H */
38190214Srpaulo
39190214Srpaulo	/*
40190214Srpaulo	 * Size of the buffer to allocate for packet data we read; this is
41190214Srpaulo	 * what the value used to be - there's no particular reason why it
42190214Srpaulo	 * should be tied to MAXDLBUF, but we'll leave it as this for now.
43190214Srpaulo	 */
44214518Srpaulo#define	MAXDLBUF	8192
45190214Srpaulo#define	PKTBUFSIZE	(MAXDLBUF * sizeof(bpf_u_int32))
46190214Srpaulo
47190214Srpaulo#endif
48190214Srpaulo
49190214Srpaulo#include <sys/types.h>
50190214Srpaulo#include <sys/time.h>
51190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H
52190214Srpaulo#include <sys/bufmod.h>
53190214Srpaulo#endif
54190214Srpaulo#include <sys/dlpi.h>
55190214Srpaulo#include <sys/stream.h>
56190214Srpaulo
57190214Srpaulo#include <errno.h>
58190214Srpaulo#include <memory.h>
59190214Srpaulo#include <stdio.h>
60190214Srpaulo#include <stdlib.h>
61190214Srpaulo#include <string.h>
62190214Srpaulo#include <stropts.h>
63190214Srpaulo#include <unistd.h>
64190214Srpaulo
65276768Sdelphij#ifdef HAVE_LIBDLPI
66276768Sdelphij#include <libdlpi.h>
67276768Sdelphij#endif
68276768Sdelphij
69190214Srpaulo#include "pcap-int.h"
70190214Srpaulo#include "dlpisubs.h"
71190214Srpaulo
72214518Srpaulo#ifdef HAVE_SYS_BUFMOD_H
73190214Srpaulostatic void pcap_stream_err(const char *, int, char *);
74214518Srpaulo#endif
75190214Srpaulo
76190214Srpaulo/*
77190214Srpaulo * Get the packet statistics.
78190214Srpaulo */
79190214Srpauloint
80190214Srpaulopcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps)
81190214Srpaulo{
82276768Sdelphij	struct pcap_dlpi *pd = p->priv;
83190214Srpaulo
84190214Srpaulo	/*
85190214Srpaulo	 * "ps_recv" counts packets handed to the filter, not packets
86190214Srpaulo	 * that passed the filter.  As filtering is done in userland,
87190214Srpaulo	 * this would not include packets dropped because we ran out
88190214Srpaulo	 * of buffer space; in order to make this more like other
89190214Srpaulo	 * platforms (Linux 2.4 and later, BSDs with BPF), where the
90190214Srpaulo	 * "packets received" count includes packets received but dropped
91190214Srpaulo	 * due to running out of buffer space, and to keep from confusing
92190214Srpaulo	 * applications that, for example, compute packet drop percentages,
93190214Srpaulo	 * we also make it count packets dropped by "bufmod" (otherwise we
94190214Srpaulo	 * might run the risk of the packet drop count being bigger than
95190214Srpaulo	 * the received-packet count).
96190214Srpaulo	 *
97190214Srpaulo	 * "ps_drop" counts packets dropped by "bufmod" because of
98190214Srpaulo	 * flow control requirements or resource exhaustion; it doesn't
99190214Srpaulo	 * count packets dropped by the interface driver, or packets
100190214Srpaulo	 * dropped upstream.  As filtering is done in userland, it counts
101190214Srpaulo	 * packets regardless of whether they would've passed the filter.
102190214Srpaulo	 *
103190214Srpaulo	 * These statistics don't include packets not yet read from
104190214Srpaulo	 * the kernel by libpcap, but they may include packets not
105190214Srpaulo	 * yet read from libpcap by the application.
106190214Srpaulo	 */
107276768Sdelphij	*ps = pd->stat;
108190214Srpaulo
109190214Srpaulo	/*
110190214Srpaulo	 * Add in the drop count, as per the above comment.
111190214Srpaulo	 */
112190214Srpaulo	ps->ps_recv += ps->ps_drop;
113190214Srpaulo	return (0);
114190214Srpaulo}
115190214Srpaulo
116190214Srpaulo/*
117190214Srpaulo * Loop through the packets and call the callback for each packet.
118190214Srpaulo * Return the number of packets read.
119190214Srpaulo */
120190214Srpauloint
121190214Srpaulopcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user,
122190214Srpaulo	int count, u_char *bufp, int len)
123190214Srpaulo{
124276768Sdelphij	struct pcap_dlpi *pd = p->priv;
125190214Srpaulo	int n, caplen, origlen;
126190214Srpaulo	u_char *ep, *pk;
127190214Srpaulo	struct pcap_pkthdr pkthdr;
128190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H
129190214Srpaulo	struct sb_hdr *sbp;
130190214Srpaulo#ifdef LBL_ALIGN
131190214Srpaulo	struct sb_hdr sbhdr;
132190214Srpaulo#endif
133190214Srpaulo#endif
134190214Srpaulo
135190214Srpaulo	/* Loop through packets */
136190214Srpaulo	ep = bufp + len;
137190214Srpaulo	n = 0;
138190214Srpaulo
139190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H
140190214Srpaulo	while (bufp < ep) {
141190214Srpaulo		/*
142190214Srpaulo		 * Has "pcap_breakloop()" been called?
143190214Srpaulo		 * If so, return immediately - if we haven't read any
144190214Srpaulo		 * packets, clear the flag and return -2 to indicate
145190214Srpaulo		 * that we were told to break out of the loop, otherwise
146190214Srpaulo		 * leave the flag set, so that the *next* call will break
147190214Srpaulo		 * out of the loop without having read any packets, and
148190214Srpaulo		 * return the number of packets we've processed so far.
149190214Srpaulo		 */
150190214Srpaulo		if (p->break_loop) {
151190214Srpaulo			if (n == 0) {
152190214Srpaulo				p->break_loop = 0;
153190214Srpaulo				return (-2);
154190214Srpaulo			} else {
155190214Srpaulo				p->bp = bufp;
156190214Srpaulo				p->cc = ep - bufp;
157190214Srpaulo				return (n);
158190214Srpaulo			}
159190214Srpaulo		}
160190214Srpaulo#ifdef LBL_ALIGN
161190214Srpaulo		if ((long)bufp & 3) {
162190214Srpaulo			sbp = &sbhdr;
163190214Srpaulo			memcpy(sbp, bufp, sizeof(*sbp));
164190214Srpaulo		} else
165190214Srpaulo#endif
166190214Srpaulo			sbp = (struct sb_hdr *)bufp;
167276768Sdelphij		pd->stat.ps_drop = sbp->sbh_drops;
168190214Srpaulo		pk = bufp + sizeof(*sbp);
169190214Srpaulo		bufp += sbp->sbh_totlen;
170190214Srpaulo		origlen = sbp->sbh_origlen;
171190214Srpaulo		caplen = sbp->sbh_msglen;
172190214Srpaulo#else
173190214Srpaulo		origlen = len;
174190214Srpaulo		caplen = min(p->snapshot, len);
175190214Srpaulo		pk = bufp;
176190214Srpaulo		bufp += caplen;
177190214Srpaulo#endif
178276768Sdelphij		++pd->stat.ps_recv;
179190214Srpaulo		if (bpf_filter(p->fcode.bf_insns, pk, origlen, caplen)) {
180190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H
181190214Srpaulo			pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec;
182190214Srpaulo			pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec;
183190214Srpaulo#else
184190214Srpaulo			(void) gettimeofday(&pkthdr.ts, NULL);
185190214Srpaulo#endif
186190214Srpaulo			pkthdr.len = origlen;
187190214Srpaulo			pkthdr.caplen = caplen;
188190214Srpaulo			/* Insure caplen does not exceed snapshot */
189190214Srpaulo			if (pkthdr.caplen > p->snapshot)
190190214Srpaulo				pkthdr.caplen = p->snapshot;
191190214Srpaulo			(*callback)(user, &pkthdr, pk);
192276768Sdelphij			if (++n >= count && !PACKET_COUNT_IS_UNLIMITED(count)) {
193190214Srpaulo				p->cc = ep - bufp;
194190214Srpaulo				p->bp = bufp;
195190214Srpaulo				return (n);
196190214Srpaulo			}
197190214Srpaulo		}
198190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H
199190214Srpaulo	}
200190214Srpaulo#endif
201190214Srpaulo	p->cc = 0;
202190214Srpaulo	return (n);
203190214Srpaulo}
204190214Srpaulo
205190214Srpaulo/*
206190214Srpaulo * Process the mac type. Returns -1 if no matching mac type found, otherwise 0.
207190214Srpaulo */
208190214Srpauloint
209190214Srpaulopcap_process_mactype(pcap_t *p, u_int mactype)
210190214Srpaulo{
211190214Srpaulo	int retv = 0;
212190214Srpaulo
213190214Srpaulo	switch (mactype) {
214190214Srpaulo
215190214Srpaulo	case DL_CSMACD:
216190214Srpaulo	case DL_ETHER:
217190214Srpaulo		p->linktype = DLT_EN10MB;
218190214Srpaulo		p->offset = 2;
219190214Srpaulo		/*
220190214Srpaulo		 * This is (presumably) a real Ethernet capture; give it a
221190214Srpaulo		 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
222190214Srpaulo		 * that an application can let you choose it, in case you're
223190214Srpaulo		 * capturing DOCSIS traffic that a Cisco Cable Modem
224190214Srpaulo		 * Termination System is putting out onto an Ethernet (it
225190214Srpaulo		 * doesn't put an Ethernet header onto the wire, it puts raw
226190214Srpaulo		 * DOCSIS frames out on the wire inside the low-level
227190214Srpaulo		 * Ethernet framing).
228190214Srpaulo		 */
229190214Srpaulo		p->dlt_list = (u_int *)malloc(sizeof(u_int) * 2);
230190214Srpaulo		/*
231190214Srpaulo		 * If that fails, just leave the list empty.
232190214Srpaulo		 */
233190214Srpaulo		if (p->dlt_list != NULL) {
234190214Srpaulo			p->dlt_list[0] = DLT_EN10MB;
235190214Srpaulo			p->dlt_list[1] = DLT_DOCSIS;
236190214Srpaulo			p->dlt_count = 2;
237190214Srpaulo		}
238190214Srpaulo		break;
239190214Srpaulo
240190214Srpaulo	case DL_FDDI:
241190214Srpaulo		p->linktype = DLT_FDDI;
242190214Srpaulo		p->offset = 3;
243190214Srpaulo		break;
244190214Srpaulo
245190214Srpaulo	case DL_TPR:
246190214Srpaulo		/* XXX - what about DL_TPB?  Is that Token Bus?  */
247190214Srpaulo		p->linktype = DLT_IEEE802;
248190214Srpaulo		p->offset = 2;
249190214Srpaulo		break;
250190214Srpaulo
251190214Srpaulo#ifdef HAVE_SOLARIS
252190214Srpaulo	case DL_IPATM:
253190214Srpaulo		p->linktype = DLT_SUNATM;
254190214Srpaulo		p->offset = 0;  /* works for LANE and LLC encapsulation */
255190214Srpaulo		break;
256190214Srpaulo#endif
257190214Srpaulo
258190214Srpaulo	default:
259190214Srpaulo		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype %u",
260190214Srpaulo		    mactype);
261190214Srpaulo		retv = -1;
262190214Srpaulo	}
263190214Srpaulo
264190214Srpaulo	return (retv);
265190214Srpaulo}
266190214Srpaulo
267190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H
268190214Srpaulo/*
269190214Srpaulo * Push and configure the buffer module. Returns -1 for error, otherwise 0.
270190214Srpaulo */
271190214Srpauloint
272276768Sdelphijpcap_conf_bufmod(pcap_t *p, int snaplen)
273190214Srpaulo{
274276768Sdelphij	struct timeval to;
275190214Srpaulo	bpf_u_int32 ss, chunksize;
276190214Srpaulo
277190214Srpaulo	/* Non-standard call to get the data nicely buffered. */
278190214Srpaulo	if (ioctl(p->fd, I_PUSH, "bufmod") != 0) {
279190214Srpaulo		pcap_stream_err("I_PUSH bufmod", errno, p->errbuf);
280276768Sdelphij		return (-1);
281190214Srpaulo	}
282190214Srpaulo
283190214Srpaulo	ss = snaplen;
284190214Srpaulo	if (ss > 0 &&
285190214Srpaulo	    strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) {
286190214Srpaulo		pcap_stream_err("SBIOCSSNAP", errno, p->errbuf);
287276768Sdelphij		return (-1);
288190214Srpaulo	}
289190214Srpaulo
290276768Sdelphij	if (p->opt.immediate) {
291276768Sdelphij		/* Set the timeout to zero, for immediate delivery. */
292276768Sdelphij		to.tv_sec = 0;
293276768Sdelphij		to.tv_usec = 0;
294190214Srpaulo		if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) {
295190214Srpaulo			pcap_stream_err("SBIOCSTIME", errno, p->errbuf);
296276768Sdelphij			return (-1);
297190214Srpaulo		}
298276768Sdelphij	} else {
299276768Sdelphij		/* Set up the bufmod timeout. */
300276768Sdelphij		if (p->opt.timeout != 0) {
301276768Sdelphij			to.tv_sec = p->opt.timeout / 1000;
302276768Sdelphij			to.tv_usec = (p->opt.timeout * 1000) % 1000000;
303276768Sdelphij			if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) {
304276768Sdelphij				pcap_stream_err("SBIOCSTIME", errno, p->errbuf);
305276768Sdelphij				return (-1);
306276768Sdelphij			}
307276768Sdelphij		}
308190214Srpaulo
309276768Sdelphij		/* Set the chunk length. */
310276768Sdelphij		chunksize = CHUNKSIZE;
311276768Sdelphij		if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize)
312276768Sdelphij		    != 0) {
313276768Sdelphij			pcap_stream_err("SBIOCSCHUNKP", errno, p->errbuf);
314276768Sdelphij			return (-1);
315276768Sdelphij		}
316190214Srpaulo	}
317190214Srpaulo
318276768Sdelphij	return (0);
319190214Srpaulo}
320190214Srpaulo#endif /* HAVE_SYS_BUFMOD_H */
321190214Srpaulo
322190214Srpaulo/*
323190214Srpaulo * Allocate data buffer. Returns -1 if memory allocation fails, else 0.
324190214Srpaulo */
325190214Srpauloint
326190214Srpaulopcap_alloc_databuf(pcap_t *p)
327190214Srpaulo{
328190214Srpaulo	p->bufsize = PKTBUFSIZE;
329190214Srpaulo	p->buffer = (u_char *)malloc(p->bufsize + p->offset);
330190214Srpaulo	if (p->buffer == NULL) {
331190214Srpaulo		strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
332190214Srpaulo		return (-1);
333190214Srpaulo	}
334190214Srpaulo
335190214Srpaulo	return (0);
336190214Srpaulo}
337190214Srpaulo
338190214Srpaulo/*
339190214Srpaulo * Issue a STREAMS I_STR ioctl. Returns -1 on error, otherwise
340190214Srpaulo * length of returned data on success.
341190214Srpaulo */
342190214Srpauloint
343190214Srpaulostrioctl(int fd, int cmd, int len, char *dp)
344190214Srpaulo{
345190214Srpaulo	struct strioctl str;
346190214Srpaulo	int retv;
347190214Srpaulo
348190214Srpaulo	str.ic_cmd = cmd;
349190214Srpaulo	str.ic_timout = -1;
350190214Srpaulo	str.ic_len = len;
351190214Srpaulo	str.ic_dp = dp;
352190214Srpaulo	if ((retv = ioctl(fd, I_STR, &str)) < 0)
353190214Srpaulo		return (retv);
354190214Srpaulo
355190214Srpaulo	return (str.ic_len);
356190214Srpaulo}
357190214Srpaulo
358214518Srpaulo#ifdef HAVE_SYS_BUFMOD_H
359190214Srpaulo/*
360190214Srpaulo * Write stream error message to errbuf.
361190214Srpaulo */
362190214Srpaulostatic void
363190214Srpaulopcap_stream_err(const char *func, int err, char *errbuf)
364190214Srpaulo{
365190214Srpaulo	snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", func, pcap_strerror(err));
366190214Srpaulo}
367214518Srpaulo#endif
368