1335640Shselasky/*
2356341Scy * pcap-dag.c: Packet capture interface for Endace DAG cards.
3335640Shselasky *
4335640Shselasky * Authors: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com)
5335640Shselasky * Modifications: Jesper Peterson
6335640Shselasky *                Koryn Grant
7356341Scy *                Stephen Donnelly <stephen.donnelly@endace.com>
8335640Shselasky */
9335640Shselasky
10335640Shselasky#ifdef HAVE_CONFIG_H
11335640Shselasky#include <config.h>
12335640Shselasky#endif
13335640Shselasky
14335640Shselasky#include <sys/param.h>			/* optionally get BSD define */
15335640Shselasky
16335640Shselasky#include <stdlib.h>
17335640Shselasky#include <string.h>
18335640Shselasky#include <errno.h>
19335640Shselasky
20335640Shselasky#include "pcap-int.h"
21335640Shselasky
22335640Shselasky#include <ctype.h>
23335640Shselasky#include <netinet/in.h>
24335640Shselasky#include <sys/mman.h>
25335640Shselasky#include <sys/socket.h>
26335640Shselasky#include <sys/types.h>
27335640Shselasky#include <unistd.h>
28335640Shselasky
29335640Shselaskystruct mbuf;		/* Squelch compiler warnings on some platforms for */
30335640Shselaskystruct rtentry;		/* declarations in <net/if.h> */
31335640Shselasky#include <net/if.h>
32335640Shselasky
33335640Shselasky#include "dagnew.h"
34335640Shselasky#include "dagapi.h"
35335640Shselasky#include "dagpci.h"
36335640Shselasky#include "dag_config_api.h"
37335640Shselasky
38335640Shselasky#include "pcap-dag.h"
39335640Shselasky
40335640Shselasky/*
41335640Shselasky * DAG devices have names beginning with "dag", followed by a number
42335640Shselasky * from 0 to DAG_MAX_BOARDS, then optionally a colon and a stream number
43335640Shselasky * from 0 to DAG_STREAM_MAX.
44335640Shselasky */
45335640Shselasky#ifndef DAG_MAX_BOARDS
46335640Shselasky#define DAG_MAX_BOARDS 32
47335640Shselasky#endif
48335640Shselasky
49335640Shselasky
50335640Shselasky#ifndef ERF_TYPE_AAL5
51335640Shselasky#define ERF_TYPE_AAL5               4
52335640Shselasky#endif
53335640Shselasky
54335640Shselasky#ifndef ERF_TYPE_MC_HDLC
55335640Shselasky#define ERF_TYPE_MC_HDLC            5
56335640Shselasky#endif
57335640Shselasky
58335640Shselasky#ifndef ERF_TYPE_MC_RAW
59335640Shselasky#define ERF_TYPE_MC_RAW             6
60335640Shselasky#endif
61335640Shselasky
62335640Shselasky#ifndef ERF_TYPE_MC_ATM
63335640Shselasky#define ERF_TYPE_MC_ATM             7
64335640Shselasky#endif
65335640Shselasky
66335640Shselasky#ifndef ERF_TYPE_MC_RAW_CHANNEL
67335640Shselasky#define ERF_TYPE_MC_RAW_CHANNEL     8
68335640Shselasky#endif
69335640Shselasky
70335640Shselasky#ifndef ERF_TYPE_MC_AAL5
71335640Shselasky#define ERF_TYPE_MC_AAL5            9
72335640Shselasky#endif
73335640Shselasky
74335640Shselasky#ifndef ERF_TYPE_COLOR_HDLC_POS
75335640Shselasky#define ERF_TYPE_COLOR_HDLC_POS     10
76335640Shselasky#endif
77335640Shselasky
78335640Shselasky#ifndef ERF_TYPE_COLOR_ETH
79335640Shselasky#define ERF_TYPE_COLOR_ETH          11
80335640Shselasky#endif
81335640Shselasky
82335640Shselasky#ifndef ERF_TYPE_MC_AAL2
83335640Shselasky#define ERF_TYPE_MC_AAL2            12
84335640Shselasky#endif
85335640Shselasky
86335640Shselasky#ifndef ERF_TYPE_IP_COUNTER
87335640Shselasky#define ERF_TYPE_IP_COUNTER         13
88335640Shselasky#endif
89335640Shselasky
90335640Shselasky#ifndef ERF_TYPE_TCP_FLOW_COUNTER
91335640Shselasky#define ERF_TYPE_TCP_FLOW_COUNTER   14
92335640Shselasky#endif
93335640Shselasky
94335640Shselasky#ifndef ERF_TYPE_DSM_COLOR_HDLC_POS
95335640Shselasky#define ERF_TYPE_DSM_COLOR_HDLC_POS 15
96335640Shselasky#endif
97335640Shselasky
98335640Shselasky#ifndef ERF_TYPE_DSM_COLOR_ETH
99335640Shselasky#define ERF_TYPE_DSM_COLOR_ETH      16
100335640Shselasky#endif
101335640Shselasky
102335640Shselasky#ifndef ERF_TYPE_COLOR_MC_HDLC_POS
103335640Shselasky#define ERF_TYPE_COLOR_MC_HDLC_POS  17
104335640Shselasky#endif
105335640Shselasky
106335640Shselasky#ifndef ERF_TYPE_AAL2
107335640Shselasky#define ERF_TYPE_AAL2               18
108335640Shselasky#endif
109335640Shselasky
110335640Shselasky#ifndef ERF_TYPE_COLOR_HASH_POS
111335640Shselasky#define ERF_TYPE_COLOR_HASH_POS     19
112335640Shselasky#endif
113335640Shselasky
114335640Shselasky#ifndef ERF_TYPE_COLOR_HASH_ETH
115335640Shselasky#define ERF_TYPE_COLOR_HASH_ETH     20
116335640Shselasky#endif
117335640Shselasky
118335640Shselasky#ifndef ERF_TYPE_INFINIBAND
119335640Shselasky#define ERF_TYPE_INFINIBAND         21
120335640Shselasky#endif
121335640Shselasky
122335640Shselasky#ifndef ERF_TYPE_IPV4
123335640Shselasky#define ERF_TYPE_IPV4               22
124335640Shselasky#endif
125335640Shselasky
126335640Shselasky#ifndef ERF_TYPE_IPV6
127335640Shselasky#define ERF_TYPE_IPV6               23
128335640Shselasky#endif
129335640Shselasky
130335640Shselasky#ifndef ERF_TYPE_RAW_LINK
131335640Shselasky#define ERF_TYPE_RAW_LINK           24
132335640Shselasky#endif
133335640Shselasky
134335640Shselasky#ifndef ERF_TYPE_INFINIBAND_LINK
135335640Shselasky#define ERF_TYPE_INFINIBAND_LINK    25
136335640Shselasky#endif
137335640Shselasky
138335640Shselasky#ifndef ERF_TYPE_META
139335640Shselasky#define ERF_TYPE_META               27
140335640Shselasky#endif
141335640Shselasky
142335640Shselasky#ifndef ERF_TYPE_PAD
143335640Shselasky#define ERF_TYPE_PAD                48
144335640Shselasky#endif
145335640Shselasky
146335640Shselasky#define ATM_CELL_SIZE		52
147335640Shselasky#define ATM_HDR_SIZE		4
148335640Shselasky
149335640Shselasky/*
150335640Shselasky * A header containing additional MTP information.
151335640Shselasky */
152335640Shselasky#define MTP2_SENT_OFFSET		0	/* 1 byte */
153335640Shselasky#define MTP2_ANNEX_A_USED_OFFSET	1	/* 1 byte */
154335640Shselasky#define MTP2_LINK_NUMBER_OFFSET		2	/* 2 bytes */
155335640Shselasky#define MTP2_HDR_LEN			4	/* length of the header */
156335640Shselasky
157335640Shselasky#define MTP2_ANNEX_A_NOT_USED      0
158335640Shselasky#define MTP2_ANNEX_A_USED          1
159335640Shselasky#define MTP2_ANNEX_A_USED_UNKNOWN  2
160335640Shselasky
161335640Shselasky/* SunATM pseudo header */
162335640Shselaskystruct sunatm_hdr {
163335640Shselasky	unsigned char	flags;		/* destination and traffic type */
164335640Shselasky	unsigned char	vpi;		/* VPI */
165335640Shselasky	unsigned short	vci;		/* VCI */
166335640Shselasky};
167335640Shselasky
168335640Shselasky/*
169335640Shselasky * Private data for capturing on DAG devices.
170335640Shselasky */
171335640Shselaskystruct pcap_dag {
172335640Shselasky	struct pcap_stat stat;
173335640Shselasky	u_char	*dag_mem_bottom;	/* DAG card current memory bottom pointer */
174335640Shselasky	u_char	*dag_mem_top;	/* DAG card current memory top pointer */
175335640Shselasky	int	dag_fcs_bits;	/* Number of checksum bits from link layer */
176335640Shselasky	int	dag_flags;	/* Flags */
177335640Shselasky	int	dag_stream;	/* DAG stream number */
178335640Shselasky	int	dag_timeout;	/* timeout specified to pcap_open_live.
179335640Shselasky				 * Same as in linux above, introduce
180335640Shselasky				 * generally? */
181335640Shselasky	dag_card_ref_t dag_ref; /* DAG Configuration/Status API card reference */
182335640Shselasky	dag_component_t dag_root;	/* DAG CSAPI Root component */
183335640Shselasky	attr_uuid_t drop_attr;  /* DAG Stream Drop Attribute handle, if available */
184335640Shselasky	struct timeval required_select_timeout;
185335640Shselasky				/* Timeout caller must use in event loops */
186335640Shselasky};
187335640Shselasky
188335640Shselaskytypedef struct pcap_dag_node {
189335640Shselasky	struct pcap_dag_node *next;
190335640Shselasky	pcap_t *p;
191335640Shselasky	pid_t pid;
192335640Shselasky} pcap_dag_node_t;
193335640Shselasky
194335640Shselaskystatic pcap_dag_node_t *pcap_dags = NULL;
195335640Shselaskystatic int atexit_handler_installed = 0;
196335640Shselaskystatic const unsigned short endian_test_word = 0x0100;
197335640Shselasky
198335640Shselasky#define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word))
199335640Shselasky
200335640Shselasky#define MAX_DAG_PACKET 65536
201335640Shselasky
202335640Shselaskystatic unsigned char TempPkt[MAX_DAG_PACKET];
203335640Shselasky
204335640Shselasky#ifndef HAVE_DAG_LARGE_STREAMS_API
205335640Shselasky#define dag_attach_stream64(a, b, c, d) dag_attach_stream(a, b, c, d)
206335640Shselasky#define dag_get_stream_poll64(a, b, c, d, e) dag_get_stream_poll(a, b, c, d, e)
207335640Shselasky#define dag_set_stream_poll64(a, b, c, d, e) dag_set_stream_poll(a, b, c, d, e)
208335640Shselasky#define dag_size_t uint32_t
209335640Shselasky#endif
210335640Shselasky
211335640Shselaskystatic int dag_setfilter(pcap_t *p, struct bpf_program *fp);
212335640Shselaskystatic int dag_stats(pcap_t *p, struct pcap_stat *ps);
213335640Shselaskystatic int dag_set_datalink(pcap_t *p, int dlt);
214335640Shselaskystatic int dag_get_datalink(pcap_t *p);
215335640Shselaskystatic int dag_setnonblock(pcap_t *p, int nonblock);
216335640Shselasky
217335640Shselaskystatic void
218335640Shselaskydelete_pcap_dag(pcap_t *p)
219335640Shselasky{
220335640Shselasky	pcap_dag_node_t *curr = NULL, *prev = NULL;
221335640Shselasky
222335640Shselasky	for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) {
223335640Shselasky		/* empty */
224335640Shselasky	}
225335640Shselasky
226335640Shselasky	if (curr != NULL && curr->p == p) {
227335640Shselasky		if (prev != NULL) {
228335640Shselasky			prev->next = curr->next;
229335640Shselasky		} else {
230335640Shselasky			pcap_dags = curr->next;
231335640Shselasky		}
232335640Shselasky	}
233335640Shselasky}
234335640Shselasky
235335640Shselasky/*
236335640Shselasky * Performs a graceful shutdown of the DAG card, frees dynamic memory held
237335640Shselasky * in the pcap_t structure, and closes the file descriptor for the DAG card.
238335640Shselasky */
239335640Shselasky
240335640Shselaskystatic void
241335640Shselaskydag_platform_cleanup(pcap_t *p)
242335640Shselasky{
243335640Shselasky	struct pcap_dag *pd = p->priv;
244335640Shselasky
245335640Shselasky	if(dag_stop_stream(p->fd, pd->dag_stream) < 0)
246335640Shselasky		fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno));
247335640Shselasky
248335640Shselasky	if(dag_detach_stream(p->fd, pd->dag_stream) < 0)
249335640Shselasky		fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno));
250335640Shselasky
251335640Shselasky	if(pd->dag_ref != NULL) {
252335640Shselasky		dag_config_dispose(pd->dag_ref);
253356341Scy		/*
254356341Scy		 * Note: we don't need to call close(p->fd) or
255356341Scy		 * dag_close(p->fd), as dag_config_dispose(pd->dag_ref)
256356341Scy		 * does this.
257356341Scy		 *
258356341Scy		 * Set p->fd to -1 to make sure that's not done.
259356341Scy		 */
260335640Shselasky		p->fd = -1;
261335640Shselasky		pd->dag_ref = NULL;
262335640Shselasky	}
263335640Shselasky	delete_pcap_dag(p);
264335640Shselasky	pcap_cleanup_live_common(p);
265335640Shselasky}
266335640Shselasky
267335640Shselaskystatic void
268335640Shselaskyatexit_handler(void)
269335640Shselasky{
270335640Shselasky	while (pcap_dags != NULL) {
271335640Shselasky		if (pcap_dags->pid == getpid()) {
272335640Shselasky			if (pcap_dags->p != NULL)
273335640Shselasky				dag_platform_cleanup(pcap_dags->p);
274335640Shselasky		} else {
275335640Shselasky			delete_pcap_dag(pcap_dags->p);
276335640Shselasky		}
277335640Shselasky	}
278335640Shselasky}
279335640Shselasky
280335640Shselaskystatic int
281335640Shselaskynew_pcap_dag(pcap_t *p)
282335640Shselasky{
283335640Shselasky	pcap_dag_node_t *node = NULL;
284335640Shselasky
285335640Shselasky	if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) {
286335640Shselasky		return -1;
287335640Shselasky	}
288335640Shselasky
289335640Shselasky	if (!atexit_handler_installed) {
290335640Shselasky		atexit(atexit_handler);
291335640Shselasky		atexit_handler_installed = 1;
292335640Shselasky	}
293335640Shselasky
294335640Shselasky	node->next = pcap_dags;
295335640Shselasky	node->p = p;
296335640Shselasky	node->pid = getpid();
297335640Shselasky
298335640Shselasky	pcap_dags = node;
299335640Shselasky
300335640Shselasky	return 0;
301335640Shselasky}
302335640Shselasky
303335640Shselaskystatic unsigned int
304335640Shselaskydag_erf_ext_header_count(uint8_t * erf, size_t len)
305335640Shselasky{
306335640Shselasky	uint32_t hdr_num = 0;
307335640Shselasky	uint8_t  hdr_type;
308335640Shselasky
309335640Shselasky	/* basic sanity checks */
310335640Shselasky	if ( erf == NULL )
311335640Shselasky		return 0;
312335640Shselasky	if ( len < 16 )
313335640Shselasky		return 0;
314335640Shselasky
315335640Shselasky	/* check if we have any extension headers */
316335640Shselasky	if ( (erf[8] & 0x80) == 0x00 )
317335640Shselasky		return 0;
318335640Shselasky
319335640Shselasky	/* loop over the extension headers */
320335640Shselasky	do {
321335640Shselasky
322335640Shselasky		/* sanity check we have enough bytes */
323335640Shselasky		if ( len < (24 + (hdr_num * 8)) )
324335640Shselasky			return hdr_num;
325335640Shselasky
326335640Shselasky		/* get the header type */
327335640Shselasky		hdr_type = erf[(16 + (hdr_num * 8))];
328335640Shselasky		hdr_num++;
329335640Shselasky
330335640Shselasky	} while ( hdr_type & 0x80 );
331335640Shselasky
332335640Shselasky	return hdr_num;
333335640Shselasky}
334335640Shselasky
335335640Shselasky/*
336335640Shselasky *  Read at most max_packets from the capture stream and call the callback
337335640Shselasky *  for each of them. Returns the number of packets handled, -1 if an
338335640Shselasky *  error occured, or -2 if we were told to break out of the loop.
339335640Shselasky */
340335640Shselaskystatic int
341335640Shselaskydag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
342335640Shselasky{
343335640Shselasky	struct pcap_dag *pd = p->priv;
344335640Shselasky	unsigned int processed = 0;
345335640Shselasky	unsigned int nonblocking = pd->dag_flags & DAGF_NONBLOCK;
346335640Shselasky	unsigned int num_ext_hdr = 0;
347335640Shselasky	unsigned int ticks_per_second;
348335640Shselasky
349335640Shselasky	/* Get the next bufferful of packets (if necessary). */
350335640Shselasky	while (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size) {
351335640Shselasky
352335640Shselasky		/*
353335640Shselasky		 * Has "pcap_breakloop()" been called?
354335640Shselasky		 */
355335640Shselasky		if (p->break_loop) {
356335640Shselasky			/*
357335640Shselasky			 * Yes - clear the flag that indicates that
358335640Shselasky			 * it has, and return -2 to indicate that
359335640Shselasky			 * we were told to break out of the loop.
360335640Shselasky			 */
361335640Shselasky			p->break_loop = 0;
362335640Shselasky			return -2;
363335640Shselasky		}
364335640Shselasky
365335640Shselasky		/* dag_advance_stream() will block (unless nonblock is called)
366335640Shselasky		 * until 64kB of data has accumulated.
367335640Shselasky		 * If to_ms is set, it will timeout before 64kB has accumulated.
368335640Shselasky		 * We wait for 64kB because processing a few packets at a time
369335640Shselasky		 * can cause problems at high packet rates (>200kpps) due
370335640Shselasky		 * to inefficiencies.
371335640Shselasky		 * This does mean if to_ms is not specified the capture may 'hang'
372335640Shselasky		 * for long periods if the data rate is extremely slow (<64kB/sec)
373335640Shselasky		 * If non-block is specified it will return immediately. The user
374335640Shselasky		 * is then responsible for efficiency.
375335640Shselasky		 */
376335640Shselasky		if ( NULL == (pd->dag_mem_top = dag_advance_stream(p->fd, pd->dag_stream, &(pd->dag_mem_bottom))) ) {
377335640Shselasky		     return -1;
378335640Shselasky		}
379335640Shselasky
380335640Shselasky		if (nonblocking && (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size))
381335640Shselasky		{
382335640Shselasky			/* Pcap is configured to process only available packets, and there aren't any, return immediately. */
383335640Shselasky			return 0;
384335640Shselasky		}
385335640Shselasky
386335640Shselasky		if(!nonblocking &&
387335640Shselasky		   pd->dag_timeout &&
388335640Shselasky		   (pd->dag_mem_top - pd->dag_mem_bottom < dag_record_size))
389335640Shselasky		{
390335640Shselasky			/* Blocking mode, but timeout set and no data has arrived, return anyway.*/
391335640Shselasky			return 0;
392335640Shselasky		}
393335640Shselasky
394335640Shselasky	}
395335640Shselasky
396335640Shselasky	/* Process the packets. */
397335640Shselasky	while (pd->dag_mem_top - pd->dag_mem_bottom >= dag_record_size) {
398335640Shselasky
399335640Shselasky		unsigned short packet_len = 0;
400335640Shselasky		int caplen = 0;
401335640Shselasky		struct pcap_pkthdr	pcap_header;
402335640Shselasky
403335640Shselasky		dag_record_t *header = (dag_record_t *)(pd->dag_mem_bottom);
404335640Shselasky
405335640Shselasky		u_char *dp = ((u_char *)header); /* + dag_record_size; */
406335640Shselasky		unsigned short rlen;
407335640Shselasky
408335640Shselasky		/*
409335640Shselasky		 * Has "pcap_breakloop()" been called?
410335640Shselasky		 */
411335640Shselasky		if (p->break_loop) {
412335640Shselasky			/*
413335640Shselasky			 * Yes - clear the flag that indicates that
414335640Shselasky			 * it has, and return -2 to indicate that
415335640Shselasky			 * we were told to break out of the loop.
416335640Shselasky			 */
417335640Shselasky			p->break_loop = 0;
418335640Shselasky			return -2;
419335640Shselasky		}
420335640Shselasky
421335640Shselasky		rlen = ntohs(header->rlen);
422335640Shselasky		if (rlen < dag_record_size)
423335640Shselasky		{
424335640Shselasky			strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE);
425335640Shselasky			return -1;
426335640Shselasky		}
427335640Shselasky		pd->dag_mem_bottom += rlen;
428335640Shselasky
429335640Shselasky		/* Count lost packets. */
430335640Shselasky		switch((header->type & 0x7f)) {
431335640Shselasky			/* in these types the color value overwrites the lctr */
432335640Shselasky		case ERF_TYPE_COLOR_HDLC_POS:
433335640Shselasky		case ERF_TYPE_COLOR_ETH:
434335640Shselasky		case ERF_TYPE_DSM_COLOR_HDLC_POS:
435335640Shselasky		case ERF_TYPE_DSM_COLOR_ETH:
436335640Shselasky		case ERF_TYPE_COLOR_MC_HDLC_POS:
437335640Shselasky		case ERF_TYPE_COLOR_HASH_ETH:
438335640Shselasky		case ERF_TYPE_COLOR_HASH_POS:
439335640Shselasky			break;
440335640Shselasky
441335640Shselasky		default:
442335640Shselasky			if ( (pd->drop_attr == kNullAttributeUuid) && (header->lctr) ) {
443335640Shselasky				pd->stat.ps_drop += ntohs(header->lctr);
444335640Shselasky			}
445335640Shselasky		}
446335640Shselasky
447335640Shselasky		if ((header->type & 0x7f) == ERF_TYPE_PAD) {
448335640Shselasky			continue;
449335640Shselasky		}
450335640Shselasky
451335640Shselasky		num_ext_hdr = dag_erf_ext_header_count(dp, rlen);
452335640Shselasky
453335640Shselasky		/* ERF encapsulation */
454335640Shselasky		/* The Extensible Record Format is not dropped for this kind of encapsulation,
455335640Shselasky		 * and will be handled as a pseudo header by the decoding application.
456335640Shselasky		 * The information carried in the ERF header and in the optional subheader (if present)
457335640Shselasky		 * could be merged with the libpcap information, to offer a better decoding.
458335640Shselasky		 * The packet length is
459335640Shselasky		 * o the length of the packet on the link (header->wlen),
460335640Shselasky		 * o plus the length of the ERF header (dag_record_size), as the length of the
461335640Shselasky		 *   pseudo header will be adjusted during the decoding,
462335640Shselasky		 * o plus the length of the optional subheader (if present).
463335640Shselasky		 *
464335640Shselasky		 * The capture length is header.rlen and the byte stuffing for alignment will be dropped
465335640Shselasky		 * if the capture length is greater than the packet length.
466335640Shselasky		 */
467335640Shselasky		if (p->linktype == DLT_ERF) {
468335640Shselasky			packet_len = ntohs(header->wlen) + dag_record_size;
469335640Shselasky			caplen = rlen;
470335640Shselasky			switch ((header->type & 0x7f)) {
471335640Shselasky			case ERF_TYPE_MC_AAL5:
472335640Shselasky			case ERF_TYPE_MC_ATM:
473335640Shselasky			case ERF_TYPE_MC_HDLC:
474335640Shselasky			case ERF_TYPE_MC_RAW_CHANNEL:
475335640Shselasky			case ERF_TYPE_MC_RAW:
476335640Shselasky			case ERF_TYPE_MC_AAL2:
477335640Shselasky			case ERF_TYPE_COLOR_MC_HDLC_POS:
478335640Shselasky				packet_len += 4; /* MC header */
479335640Shselasky				break;
480335640Shselasky
481335640Shselasky			case ERF_TYPE_COLOR_HASH_ETH:
482335640Shselasky			case ERF_TYPE_DSM_COLOR_ETH:
483335640Shselasky			case ERF_TYPE_COLOR_ETH:
484335640Shselasky			case ERF_TYPE_ETH:
485335640Shselasky				packet_len += 2; /* ETH header */
486335640Shselasky				break;
487335640Shselasky			} /* switch type */
488335640Shselasky
489335640Shselasky			/* Include ERF extension headers */
490335640Shselasky			packet_len += (8 * num_ext_hdr);
491335640Shselasky
492335640Shselasky			if (caplen > packet_len) {
493335640Shselasky				caplen = packet_len;
494335640Shselasky			}
495335640Shselasky		} else {
496335640Shselasky			/* Other kind of encapsulation according to the header Type */
497335640Shselasky
498335640Shselasky			/* Skip over generic ERF header */
499335640Shselasky			dp += dag_record_size;
500335640Shselasky			/* Skip over extension headers */
501335640Shselasky			dp += 8 * num_ext_hdr;
502335640Shselasky
503335640Shselasky			switch((header->type & 0x7f)) {
504335640Shselasky			case ERF_TYPE_ATM:
505335640Shselasky			case ERF_TYPE_AAL5:
506335640Shselasky				if ((header->type & 0x7f) == ERF_TYPE_AAL5) {
507335640Shselasky					packet_len = ntohs(header->wlen);
508335640Shselasky					caplen = rlen - dag_record_size;
509335640Shselasky				}
510335640Shselasky			case ERF_TYPE_MC_ATM:
511335640Shselasky				if ((header->type & 0x7f) == ERF_TYPE_MC_ATM) {
512335640Shselasky					caplen = packet_len = ATM_CELL_SIZE;
513335640Shselasky					dp+=4;
514335640Shselasky				}
515335640Shselasky			case ERF_TYPE_MC_AAL5:
516335640Shselasky				if ((header->type & 0x7f) == ERF_TYPE_MC_AAL5) {
517335640Shselasky					packet_len = ntohs(header->wlen);
518335640Shselasky					caplen = rlen - dag_record_size - 4;
519335640Shselasky					dp+=4;
520335640Shselasky				}
521335640Shselasky				/* Skip over extension headers */
522335640Shselasky				caplen -= (8 * num_ext_hdr);
523335640Shselasky
524335640Shselasky				if ((header->type & 0x7f) == ERF_TYPE_ATM) {
525335640Shselasky					caplen = packet_len = ATM_CELL_SIZE;
526335640Shselasky				}
527335640Shselasky				if (p->linktype == DLT_SUNATM) {
528335640Shselasky					struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp;
529335640Shselasky					unsigned long rawatm;
530335640Shselasky
531335640Shselasky					rawatm = ntohl(*((unsigned long *)dp));
532335640Shselasky					sunatm->vci = htons((rawatm >>  4) & 0xffff);
533335640Shselasky					sunatm->vpi = (rawatm >> 20) & 0x00ff;
534335640Shselasky					sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) |
535335640Shselasky						((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 :
536335640Shselasky						 ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 :
537335640Shselasky						  ((dp[ATM_HDR_SIZE] == 0xaa &&
538335640Shselasky						    dp[ATM_HDR_SIZE+1] == 0xaa &&
539335640Shselasky						    dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1)));
540335640Shselasky
541335640Shselasky				} else if (p->linktype == DLT_ATM_RFC1483) {
542335640Shselasky					packet_len -= ATM_HDR_SIZE;
543335640Shselasky					caplen -= ATM_HDR_SIZE;
544335640Shselasky					dp += ATM_HDR_SIZE;
545335640Shselasky				} else
546335640Shselasky					continue;
547335640Shselasky				break;
548335640Shselasky
549335640Shselasky			case ERF_TYPE_COLOR_HASH_ETH:
550335640Shselasky			case ERF_TYPE_DSM_COLOR_ETH:
551335640Shselasky			case ERF_TYPE_COLOR_ETH:
552335640Shselasky			case ERF_TYPE_ETH:
553335640Shselasky				if ((p->linktype != DLT_EN10MB) &&
554335640Shselasky				    (p->linktype != DLT_DOCSIS))
555335640Shselasky					continue;
556335640Shselasky				packet_len = ntohs(header->wlen);
557335640Shselasky				packet_len -= (pd->dag_fcs_bits >> 3);
558335640Shselasky				caplen = rlen - dag_record_size - 2;
559335640Shselasky				/* Skip over extension headers */
560335640Shselasky				caplen -= (8 * num_ext_hdr);
561335640Shselasky				if (caplen > packet_len) {
562335640Shselasky					caplen = packet_len;
563335640Shselasky				}
564335640Shselasky				dp += 2;
565335640Shselasky				break;
566335640Shselasky
567335640Shselasky			case ERF_TYPE_COLOR_HASH_POS:
568335640Shselasky			case ERF_TYPE_DSM_COLOR_HDLC_POS:
569335640Shselasky			case ERF_TYPE_COLOR_HDLC_POS:
570335640Shselasky			case ERF_TYPE_HDLC_POS:
571335640Shselasky				if ((p->linktype != DLT_CHDLC) &&
572335640Shselasky				    (p->linktype != DLT_PPP_SERIAL) &&
573335640Shselasky				    (p->linktype != DLT_FRELAY))
574335640Shselasky					continue;
575335640Shselasky				packet_len = ntohs(header->wlen);
576335640Shselasky				packet_len -= (pd->dag_fcs_bits >> 3);
577335640Shselasky				caplen = rlen - dag_record_size;
578335640Shselasky				/* Skip over extension headers */
579335640Shselasky				caplen -= (8 * num_ext_hdr);
580335640Shselasky				if (caplen > packet_len) {
581335640Shselasky					caplen = packet_len;
582335640Shselasky				}
583335640Shselasky				break;
584335640Shselasky
585335640Shselasky			case ERF_TYPE_COLOR_MC_HDLC_POS:
586335640Shselasky			case ERF_TYPE_MC_HDLC:
587335640Shselasky				if ((p->linktype != DLT_CHDLC) &&
588335640Shselasky				    (p->linktype != DLT_PPP_SERIAL) &&
589335640Shselasky				    (p->linktype != DLT_FRELAY) &&
590335640Shselasky				    (p->linktype != DLT_MTP2) &&
591335640Shselasky				    (p->linktype != DLT_MTP2_WITH_PHDR) &&
592335640Shselasky				    (p->linktype != DLT_LAPD))
593335640Shselasky					continue;
594335640Shselasky				packet_len = ntohs(header->wlen);
595335640Shselasky				packet_len -= (pd->dag_fcs_bits >> 3);
596335640Shselasky				caplen = rlen - dag_record_size - 4;
597335640Shselasky				/* Skip over extension headers */
598335640Shselasky				caplen -= (8 * num_ext_hdr);
599335640Shselasky				if (caplen > packet_len) {
600335640Shselasky					caplen = packet_len;
601335640Shselasky				}
602335640Shselasky				/* jump the MC_HDLC_HEADER */
603335640Shselasky				dp += 4;
604335640Shselasky#ifdef DLT_MTP2_WITH_PHDR
605335640Shselasky				if (p->linktype == DLT_MTP2_WITH_PHDR) {
606335640Shselasky					/* Add the MTP2 Pseudo Header */
607335640Shselasky					caplen += MTP2_HDR_LEN;
608335640Shselasky					packet_len += MTP2_HDR_LEN;
609335640Shselasky
610335640Shselasky					TempPkt[MTP2_SENT_OFFSET] = 0;
611335640Shselasky					TempPkt[MTP2_ANNEX_A_USED_OFFSET] = MTP2_ANNEX_A_USED_UNKNOWN;
612335640Shselasky					*(TempPkt+MTP2_LINK_NUMBER_OFFSET) = ((header->rec.mc_hdlc.mc_header>>16)&0x01);
613335640Shselasky					*(TempPkt+MTP2_LINK_NUMBER_OFFSET+1) = ((header->rec.mc_hdlc.mc_header>>24)&0xff);
614335640Shselasky					memcpy(TempPkt+MTP2_HDR_LEN, dp, caplen);
615335640Shselasky					dp = TempPkt;
616335640Shselasky				}
617335640Shselasky#endif
618335640Shselasky				break;
619335640Shselasky
620335640Shselasky			case ERF_TYPE_IPV4:
621335640Shselasky				if ((p->linktype != DLT_RAW) &&
622335640Shselasky				    (p->linktype != DLT_IPV4))
623335640Shselasky					continue;
624335640Shselasky				packet_len = ntohs(header->wlen);
625335640Shselasky				caplen = rlen - dag_record_size;
626335640Shselasky				/* Skip over extension headers */
627335640Shselasky				caplen -= (8 * num_ext_hdr);
628335640Shselasky				if (caplen > packet_len) {
629335640Shselasky					caplen = packet_len;
630335640Shselasky				}
631335640Shselasky				break;
632335640Shselasky
633335640Shselasky			case ERF_TYPE_IPV6:
634335640Shselasky				if ((p->linktype != DLT_RAW) &&
635335640Shselasky				    (p->linktype != DLT_IPV6))
636335640Shselasky					continue;
637335640Shselasky				packet_len = ntohs(header->wlen);
638335640Shselasky				caplen = rlen - dag_record_size;
639335640Shselasky				/* Skip over extension headers */
640335640Shselasky				caplen -= (8 * num_ext_hdr);
641335640Shselasky				if (caplen > packet_len) {
642335640Shselasky					caplen = packet_len;
643335640Shselasky				}
644335640Shselasky				break;
645335640Shselasky
646335640Shselasky			/* These types have no matching 'native' DLT, but can be used with DLT_ERF above */
647335640Shselasky			case ERF_TYPE_MC_RAW:
648335640Shselasky			case ERF_TYPE_MC_RAW_CHANNEL:
649335640Shselasky			case ERF_TYPE_IP_COUNTER:
650335640Shselasky			case ERF_TYPE_TCP_FLOW_COUNTER:
651335640Shselasky			case ERF_TYPE_INFINIBAND:
652335640Shselasky			case ERF_TYPE_RAW_LINK:
653335640Shselasky			case ERF_TYPE_INFINIBAND_LINK:
654335640Shselasky			default:
655335640Shselasky				/* Unhandled ERF type.
656335640Shselasky				 * Ignore rather than generating error
657335640Shselasky				 */
658335640Shselasky				continue;
659335640Shselasky			} /* switch type */
660335640Shselasky
661335640Shselasky		} /* ERF encapsulation */
662335640Shselasky
663335640Shselasky		if (caplen > p->snapshot)
664335640Shselasky			caplen = p->snapshot;
665335640Shselasky
666335640Shselasky		/* Run the packet filter if there is one. */
667335640Shselasky		if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
668335640Shselasky
669335640Shselasky			/* convert between timestamp formats */
670335640Shselasky			register unsigned long long ts;
671335640Shselasky
672335640Shselasky			if (IS_BIGENDIAN()) {
673335640Shselasky				ts = SWAPLL(header->ts);
674335640Shselasky			} else {
675335640Shselasky				ts = header->ts;
676335640Shselasky			}
677335640Shselasky
678335640Shselasky			switch (p->opt.tstamp_precision) {
679335640Shselasky			case PCAP_TSTAMP_PRECISION_NANO:
680335640Shselasky				ticks_per_second = 1000000000;
681335640Shselasky				break;
682335640Shselasky			case PCAP_TSTAMP_PRECISION_MICRO:
683335640Shselasky			default:
684335640Shselasky				ticks_per_second = 1000000;
685335640Shselasky				break;
686335640Shselasky
687335640Shselasky			}
688335640Shselasky			pcap_header.ts.tv_sec = ts >> 32;
689335640Shselasky			ts = (ts & 0xffffffffULL) * ticks_per_second;
690335640Shselasky			ts += 0x80000000; /* rounding */
691335640Shselasky			pcap_header.ts.tv_usec = ts >> 32;
692335640Shselasky			if (pcap_header.ts.tv_usec >= ticks_per_second) {
693335640Shselasky				pcap_header.ts.tv_usec -= ticks_per_second;
694335640Shselasky				pcap_header.ts.tv_sec++;
695335640Shselasky			}
696335640Shselasky
697335640Shselasky			/* Fill in our own header data */
698335640Shselasky			pcap_header.caplen = caplen;
699335640Shselasky			pcap_header.len = packet_len;
700335640Shselasky
701335640Shselasky			/* Count the packet. */
702335640Shselasky			pd->stat.ps_recv++;
703335640Shselasky
704335640Shselasky			/* Call the user supplied callback function */
705335640Shselasky			callback(user, &pcap_header, dp);
706335640Shselasky
707335640Shselasky			/* Only count packets that pass the filter, for consistency with standard Linux behaviour. */
708335640Shselasky			processed++;
709335640Shselasky			if (processed == cnt && !PACKET_COUNT_IS_UNLIMITED(cnt))
710335640Shselasky			{
711335640Shselasky				/* Reached the user-specified limit. */
712335640Shselasky				return cnt;
713335640Shselasky			}
714335640Shselasky		}
715335640Shselasky	}
716335640Shselasky
717335640Shselasky	return processed;
718335640Shselasky}
719335640Shselasky
720335640Shselaskystatic int
721335640Shselaskydag_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
722335640Shselasky{
723356341Scy	pcap_strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards",
724335640Shselasky	    PCAP_ERRBUF_SIZE);
725335640Shselasky	return (-1);
726335640Shselasky}
727335640Shselasky
728335640Shselasky/*
729335640Shselasky *  Get a handle for a live capture from the given DAG device.  Passing a NULL
730335640Shselasky *  device will result in a failure.  The promisc flag is ignored because DAG
731335640Shselasky *  cards are always promiscuous.  The to_ms parameter is used in setting the
732335640Shselasky *  API polling parameters.
733335640Shselasky *
734335640Shselasky *  snaplen is now also ignored, until we get per-stream slen support. Set
735335640Shselasky *  slen with approprite DAG tool BEFORE pcap_activate().
736335640Shselasky *
737335640Shselasky *  See also pcap(3).
738335640Shselasky */
739335640Shselaskystatic int dag_activate(pcap_t* p)
740335640Shselasky{
741335640Shselasky	struct pcap_dag *pd = p->priv;
742335640Shselasky	char *s;
743335640Shselasky	int n;
744335640Shselasky	daginf_t* daginf;
745335640Shselasky	char * newDev = NULL;
746335640Shselasky	char * device = p->opt.device;
747356341Scy	int ret;
748335640Shselasky	dag_size_t mindata;
749335640Shselasky	struct timeval maxwait;
750335640Shselasky	struct timeval poll;
751335640Shselasky
752335640Shselasky	if (device == NULL) {
753335640Shselasky		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "device is NULL");
754356341Scy		return PCAP_ERROR;
755335640Shselasky	}
756335640Shselasky
757335640Shselasky	/* Initialize some components of the pcap structure. */
758335640Shselasky	newDev = (char *)malloc(strlen(device) + 16);
759335640Shselasky	if (newDev == NULL) {
760356341Scy		ret = PCAP_ERROR;
761335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
762335640Shselasky		    errno, "Can't allocate string for device name");
763335640Shselasky		goto fail;
764335640Shselasky	}
765335640Shselasky
766335640Shselasky	/* Parse input name to get dag device and stream number if provided */
767335640Shselasky	if (dag_parse_name(device, newDev, strlen(device) + 16, &pd->dag_stream) < 0) {
768356341Scy		/*
769356341Scy		 * XXX - it'd be nice if this indicated what was wrong
770356341Scy		 * with the name.  Does this reliably set errno?
771356341Scy		 * Should this return PCAP_ERROR_NO_SUCH_DEVICE in some
772356341Scy		 * cases?
773356341Scy		 */
774356341Scy		ret = PCAP_ERROR;
775335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
776335640Shselasky		    errno, "dag_parse_name");
777335640Shselasky		goto fail;
778335640Shselasky	}
779335640Shselasky	device = newDev;
780335640Shselasky
781335640Shselasky	if (pd->dag_stream%2) {
782356341Scy		ret = PCAP_ERROR;
783335640Shselasky		pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "dag_parse_name: tx (even numbered) streams not supported for capture");
784335640Shselasky		goto fail;
785335640Shselasky	}
786335640Shselasky
787335640Shselasky	/* setup device parameters */
788335640Shselasky	if((pd->dag_ref = dag_config_init((char *)device)) == NULL) {
789356341Scy		/*
790356341Scy		 * XXX - does this reliably set errno?
791356341Scy		 */
792356341Scy		if (errno == ENOENT)
793356341Scy			ret = PCAP_ERROR_NO_SUCH_DEVICE;
794356341Scy		else if (errno == EPERM || errno == EACCES)
795356341Scy			ret = PCAP_ERROR_PERM_DENIED;
796356341Scy		else
797356341Scy			ret = PCAP_ERROR;
798335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
799335640Shselasky		    errno, "dag_config_init %s", device);
800335640Shselasky		goto fail;
801335640Shselasky	}
802335640Shselasky
803335640Shselasky	if((p->fd = dag_config_get_card_fd(pd->dag_ref)) < 0) {
804356341Scy		/*
805356341Scy		 * XXX - does this reliably set errno?
806356341Scy		 */
807356341Scy		ret = PCAP_ERROR;
808335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
809335640Shselasky		    errno, "dag_config_get_card_fd %s", device);
810356341Scy		goto failclose;
811335640Shselasky	}
812335640Shselasky
813335640Shselasky	/* Open requested stream. Can fail if already locked or on error */
814335640Shselasky	if (dag_attach_stream64(p->fd, pd->dag_stream, 0, 0) < 0) {
815356341Scy		ret = PCAP_ERROR;
816335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
817335640Shselasky		    errno, "dag_attach_stream");
818335640Shselasky		goto failclose;
819335640Shselasky	}
820335640Shselasky
821335640Shselasky	/* Try to find Stream Drop attribute */
822335640Shselasky	pd->drop_attr = kNullAttributeUuid;
823335640Shselasky	pd->dag_root = dag_config_get_root_component(pd->dag_ref);
824335640Shselasky	if ( dag_component_get_subcomponent(pd->dag_root, kComponentStreamFeatures, 0) )
825335640Shselasky	{
826335640Shselasky		pd->drop_attr = dag_config_get_indexed_attribute_uuid(pd->dag_ref, kUint32AttributeStreamDropCount, pd->dag_stream/2);
827335640Shselasky	}
828335640Shselasky
829335640Shselasky	/* Set up default poll parameters for stream
830335640Shselasky	 * Can be overridden by pcap_set_nonblock()
831335640Shselasky	 */
832335640Shselasky	if (dag_get_stream_poll64(p->fd, pd->dag_stream,
833335640Shselasky				&mindata, &maxwait, &poll) < 0) {
834356341Scy		ret = PCAP_ERROR;
835335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
836335640Shselasky		    errno, "dag_get_stream_poll");
837335640Shselasky		goto faildetach;
838335640Shselasky	}
839335640Shselasky
840335640Shselasky	/* Use the poll time as the required select timeout for callers
841335640Shselasky	 * who are using select()/etc. in an event loop waiting for
842335640Shselasky	 * packets to arrive.
843335640Shselasky	 */
844335640Shselasky	pd->required_select_timeout = poll;
845335640Shselasky	p->required_select_timeout = &pd->required_select_timeout;
846335640Shselasky
847335640Shselasky	/*
848335640Shselasky	 * Turn a negative snapshot value (invalid), a snapshot value of
849335640Shselasky	 * 0 (unspecified), or a value bigger than the normal maximum
850335640Shselasky	 * value, into the maximum allowed value.
851335640Shselasky	 *
852335640Shselasky	 * If some application really *needs* a bigger snapshot
853335640Shselasky	 * length, we should just increase MAXIMUM_SNAPLEN.
854335640Shselasky	 */
855335640Shselasky	if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
856335640Shselasky		p->snapshot = MAXIMUM_SNAPLEN;
857335640Shselasky
858335640Shselasky	if (p->opt.immediate) {
859335640Shselasky		/* Call callback immediately.
860335640Shselasky		 * XXX - is this the right way to p this?
861335640Shselasky		 */
862335640Shselasky		mindata = 0;
863335640Shselasky	} else {
864335640Shselasky		/* Amount of data to collect in Bytes before calling callbacks.
865335640Shselasky		 * Important for efficiency, but can introduce latency
866335640Shselasky		 * at low packet rates if to_ms not set!
867335640Shselasky		 */
868335640Shselasky		mindata = 65536;
869335640Shselasky	}
870335640Shselasky
871335640Shselasky	/* Obey opt.timeout (was to_ms) if supplied. This is a good idea!
872335640Shselasky	 * Recommend 10-100ms. Calls will time out even if no data arrived.
873335640Shselasky	 */
874335640Shselasky	maxwait.tv_sec = p->opt.timeout/1000;
875335640Shselasky	maxwait.tv_usec = (p->opt.timeout%1000) * 1000;
876335640Shselasky
877335640Shselasky	if (dag_set_stream_poll64(p->fd, pd->dag_stream,
878335640Shselasky				mindata, &maxwait, &poll) < 0) {
879356341Scy		ret = PCAP_ERROR;
880335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
881335640Shselasky		    errno, "dag_set_stream_poll");
882335640Shselasky		goto faildetach;
883335640Shselasky	}
884335640Shselasky
885335640Shselasky        /* XXX Not calling dag_configure() to set slen; this is unsafe in
886335640Shselasky	 * multi-stream environments as the gpp config is global.
887335640Shselasky         * Once the firmware provides 'per-stream slen' this can be supported
888335640Shselasky	 * again via the Config API without side-effects */
889335640Shselasky#if 0
890335640Shselasky	/* set the card snap length to the specified snaplen parameter */
891335640Shselasky	/* This is a really bad idea, as different cards have different
892335640Shselasky	 * valid slen ranges. Should fix in Config API. */
893335640Shselasky	if (p->snapshot == 0 || p->snapshot > MAX_DAG_SNAPLEN) {
894335640Shselasky		p->snapshot = MAX_DAG_SNAPLEN;
895335640Shselasky	} else if (snaplen < MIN_DAG_SNAPLEN) {
896335640Shselasky		p->snapshot = MIN_DAG_SNAPLEN;
897335640Shselasky	}
898335640Shselasky	/* snap len has to be a multiple of 4 */
899335640Shselasky#endif
900335640Shselasky
901335640Shselasky	if(dag_start_stream(p->fd, pd->dag_stream) < 0) {
902356341Scy		ret = PCAP_ERROR;
903335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
904335640Shselasky		    errno, "dag_start_stream %s", device);
905335640Shselasky		goto faildetach;
906335640Shselasky	}
907335640Shselasky
908335640Shselasky	/*
909335640Shselasky	 * Important! You have to ensure bottom is properly
910335640Shselasky	 * initialized to zero on startup, it won't give you
911335640Shselasky	 * a compiler warning if you make this mistake!
912335640Shselasky	 */
913335640Shselasky	pd->dag_mem_bottom = 0;
914335640Shselasky	pd->dag_mem_top = 0;
915335640Shselasky
916335640Shselasky	/*
917335640Shselasky	 * Find out how many FCS bits we should strip.
918335640Shselasky	 * First, query the card to see if it strips the FCS.
919335640Shselasky	 */
920335640Shselasky	daginf = dag_info(p->fd);
921335640Shselasky	if ((0x4200 == daginf->device_code) || (0x4230 == daginf->device_code))	{
922335640Shselasky		/* DAG 4.2S and 4.23S already strip the FCS.  Stripping the final word again truncates the packet. */
923335640Shselasky		pd->dag_fcs_bits = 0;
924335640Shselasky
925335640Shselasky		/* Note that no FCS will be supplied. */
926335640Shselasky		p->linktype_ext = LT_FCS_DATALINK_EXT(0);
927335640Shselasky	} else {
928335640Shselasky		/*
929335640Shselasky		 * Start out assuming it's 32 bits.
930335640Shselasky		 */
931335640Shselasky		pd->dag_fcs_bits = 32;
932335640Shselasky
933335640Shselasky		/* Allow an environment variable to override. */
934335640Shselasky		if ((s = getenv("ERF_FCS_BITS")) != NULL) {
935335640Shselasky			if ((n = atoi(s)) == 0 || n == 16 || n == 32) {
936335640Shselasky				pd->dag_fcs_bits = n;
937335640Shselasky			} else {
938356341Scy				ret = PCAP_ERROR;
939335640Shselasky				pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
940335640Shselasky					"pcap_activate %s: bad ERF_FCS_BITS value (%d) in environment", device, n);
941335640Shselasky				goto failstop;
942335640Shselasky			}
943335640Shselasky		}
944335640Shselasky
945335640Shselasky		/*
946335640Shselasky		 * Did the user request that they not be stripped?
947335640Shselasky		 */
948335640Shselasky		if ((s = getenv("ERF_DONT_STRIP_FCS")) != NULL) {
949335640Shselasky			/* Yes.  Note the number of bytes that will be
950335640Shselasky			   supplied. */
951335640Shselasky			p->linktype_ext = LT_FCS_DATALINK_EXT(pd->dag_fcs_bits/16);
952335640Shselasky
953335640Shselasky			/* And don't strip them. */
954335640Shselasky			pd->dag_fcs_bits = 0;
955335640Shselasky		}
956335640Shselasky	}
957335640Shselasky
958335640Shselasky	pd->dag_timeout	= p->opt.timeout;
959335640Shselasky
960335640Shselasky	p->linktype = -1;
961356341Scy	if (dag_get_datalink(p) < 0) {
962356341Scy		ret = PCAP_ERROR;
963335640Shselasky		goto failstop;
964356341Scy	}
965335640Shselasky
966335640Shselasky	p->bufsize = 0;
967335640Shselasky
968335640Shselasky	if (new_pcap_dag(p) < 0) {
969356341Scy		ret = PCAP_ERROR;
970335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
971335640Shselasky		    errno, "new_pcap_dag %s", device);
972335640Shselasky		goto failstop;
973335640Shselasky	}
974335640Shselasky
975335640Shselasky	/*
976335640Shselasky	 * "select()" and "poll()" don't work on DAG device descriptors.
977335640Shselasky	 */
978335640Shselasky	p->selectable_fd = -1;
979335640Shselasky
980335640Shselasky	if (newDev != NULL) {
981335640Shselasky		free((char *)newDev);
982335640Shselasky	}
983335640Shselasky
984335640Shselasky	p->read_op = dag_read;
985335640Shselasky	p->inject_op = dag_inject;
986335640Shselasky	p->setfilter_op = dag_setfilter;
987335640Shselasky	p->setdirection_op = NULL; /* Not implemented.*/
988335640Shselasky	p->set_datalink_op = dag_set_datalink;
989335640Shselasky	p->getnonblock_op = pcap_getnonblock_fd;
990335640Shselasky	p->setnonblock_op = dag_setnonblock;
991335640Shselasky	p->stats_op = dag_stats;
992335640Shselasky	p->cleanup_op = dag_platform_cleanup;
993335640Shselasky	pd->stat.ps_drop = 0;
994335640Shselasky	pd->stat.ps_recv = 0;
995335640Shselasky	pd->stat.ps_ifdrop = 0;
996335640Shselasky	return 0;
997335640Shselasky
998335640Shselaskyfailstop:
999335640Shselasky	if (dag_stop_stream(p->fd, pd->dag_stream) < 0) {
1000335640Shselasky		fprintf(stderr,"dag_stop_stream: %s\n", strerror(errno));
1001335640Shselasky	}
1002335640Shselasky
1003335640Shselaskyfaildetach:
1004335640Shselasky	if (dag_detach_stream(p->fd, pd->dag_stream) < 0)
1005335640Shselasky		fprintf(stderr,"dag_detach_stream: %s\n", strerror(errno));
1006335640Shselasky
1007335640Shselaskyfailclose:
1008335640Shselasky	dag_config_dispose(pd->dag_ref);
1009356341Scy	/*
1010356341Scy	 * Note: we don't need to call close(p->fd) or dag_close(p->fd),
1011356341Scy	 * as dag_config_dispose(pd->dag_ref) does this.
1012356341Scy	 *
1013356341Scy	 * Set p->fd to -1 to make sure that's not done.
1014356341Scy	 */
1015356341Scy	p->fd = -1;
1016356341Scy	pd->dag_ref = NULL;
1017335640Shselasky	delete_pcap_dag(p);
1018335640Shselasky
1019335640Shselaskyfail:
1020335640Shselasky	pcap_cleanup_live_common(p);
1021335640Shselasky	if (newDev != NULL) {
1022335640Shselasky		free((char *)newDev);
1023335640Shselasky	}
1024335640Shselasky
1025356341Scy	return ret;
1026335640Shselasky}
1027335640Shselasky
1028335640Shselaskypcap_t *dag_create(const char *device, char *ebuf, int *is_ours)
1029335640Shselasky{
1030335640Shselasky	const char *cp;
1031335640Shselasky	char *cpend;
1032335640Shselasky	long devnum;
1033335640Shselasky	pcap_t *p;
1034335640Shselasky	long stream = 0;
1035335640Shselasky
1036335640Shselasky	/* Does this look like a DAG device? */
1037335640Shselasky	cp = strrchr(device, '/');
1038335640Shselasky	if (cp == NULL)
1039335640Shselasky		cp = device;
1040335640Shselasky	/* Does it begin with "dag"? */
1041335640Shselasky	if (strncmp(cp, "dag", 3) != 0) {
1042335640Shselasky		/* Nope, doesn't begin with "dag" */
1043335640Shselasky		*is_ours = 0;
1044335640Shselasky		return NULL;
1045335640Shselasky	}
1046335640Shselasky	/* Yes - is "dag" followed by a number from 0 to DAG_MAX_BOARDS-1 */
1047335640Shselasky	cp += 3;
1048335640Shselasky	devnum = strtol(cp, &cpend, 10);
1049335640Shselasky	if (*cpend == ':') {
1050335640Shselasky		/* Followed by a stream number. */
1051335640Shselasky		stream = strtol(++cpend, &cpend, 10);
1052335640Shselasky	}
1053335640Shselasky
1054335640Shselasky	if (cpend == cp || *cpend != '\0') {
1055335640Shselasky		/* Not followed by a number. */
1056335640Shselasky		*is_ours = 0;
1057335640Shselasky		return NULL;
1058335640Shselasky	}
1059335640Shselasky
1060335640Shselasky	if (devnum < 0 || devnum >= DAG_MAX_BOARDS) {
1061335640Shselasky		/* Followed by a non-valid number. */
1062335640Shselasky		*is_ours = 0;
1063335640Shselasky		return NULL;
1064335640Shselasky	}
1065335640Shselasky
1066335640Shselasky	if (stream <0 || stream >= DAG_STREAM_MAX) {
1067335640Shselasky		/* Followed by a non-valid stream number. */
1068335640Shselasky		*is_ours = 0;
1069335640Shselasky		return NULL;
1070335640Shselasky	}
1071335640Shselasky
1072335640Shselasky	/* OK, it's probably ours. */
1073335640Shselasky	*is_ours = 1;
1074335640Shselasky
1075335640Shselasky	p = pcap_create_common(ebuf, sizeof (struct pcap_dag));
1076335640Shselasky	if (p == NULL)
1077335640Shselasky		return NULL;
1078335640Shselasky
1079335640Shselasky	p->activate_op = dag_activate;
1080335640Shselasky
1081335640Shselasky	/*
1082335640Shselasky	 * We claim that we support microsecond and nanosecond time
1083335640Shselasky	 * stamps.
1084335640Shselasky	 *
1085335640Shselasky	 * XXX Our native precision is 2^-32s, but libpcap doesn't support
1086335640Shselasky	 * power of two precisions yet. We can convert to either MICRO or NANO.
1087335640Shselasky	 */
1088335640Shselasky	p->tstamp_precision_count = 2;
1089335640Shselasky	p->tstamp_precision_list = malloc(2 * sizeof(u_int));
1090335640Shselasky	if (p->tstamp_precision_list == NULL) {
1091335640Shselasky		pcap_fmt_errmsg_for_errno(ebuf, PCAP_ERRBUF_SIZE,
1092335640Shselasky		    errno, "malloc");
1093335640Shselasky		pcap_close(p);
1094335640Shselasky		return NULL;
1095335640Shselasky	}
1096335640Shselasky	p->tstamp_precision_list[0] = PCAP_TSTAMP_PRECISION_MICRO;
1097335640Shselasky	p->tstamp_precision_list[1] = PCAP_TSTAMP_PRECISION_NANO;
1098335640Shselasky	return p;
1099335640Shselasky}
1100335640Shselasky
1101335640Shselaskystatic int
1102335640Shselaskydag_stats(pcap_t *p, struct pcap_stat *ps) {
1103335640Shselasky	struct pcap_dag *pd = p->priv;
1104335640Shselasky	uint32_t stream_drop;
1105335640Shselasky	dag_err_t dag_error;
1106335640Shselasky
1107335640Shselasky	/*
1108335640Shselasky	 * Packet records received (ps_recv) are counted in dag_read().
1109335640Shselasky	 * Packet records dropped (ps_drop) are read from Stream Drop attribute if present,
1110335640Shselasky	 * otherwise integrate the ERF Header lctr counts (if available) in dag_read().
1111335640Shselasky	 * We are reporting that no records are dropped by the card/driver (ps_ifdrop).
1112335640Shselasky	 */
1113335640Shselasky
1114335640Shselasky	if(pd->drop_attr != kNullAttributeUuid) {
1115335640Shselasky		/* Note this counter is cleared at start of capture and will wrap at UINT_MAX.
1116335640Shselasky		 * The application is responsible for polling ps_drop frequently enough
1117335640Shselasky		 * to detect each wrap and integrate total drop with a wider counter */
1118335640Shselasky		if ((dag_error = dag_config_get_uint32_attribute_ex(pd->dag_ref, pd->drop_attr, &stream_drop) == kDagErrNone)) {
1119335640Shselasky			pd->stat.ps_drop = stream_drop;
1120335640Shselasky		} else {
1121335640Shselasky			pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "reading stream drop attribute: %s",
1122335640Shselasky				 dag_config_strerror(dag_error));
1123335640Shselasky			return -1;
1124335640Shselasky		}
1125335640Shselasky	}
1126335640Shselasky
1127335640Shselasky	*ps = pd->stat;
1128335640Shselasky
1129335640Shselasky	return 0;
1130335640Shselasky}
1131335640Shselasky
1132335640Shselasky/*
1133335640Shselasky * Add all DAG devices.
1134335640Shselasky */
1135335640Shselaskyint
1136335640Shselaskydag_findalldevs(pcap_if_list_t *devlistp, char *errbuf)
1137335640Shselasky{
1138335640Shselasky	char name[12];	/* XXX - pick a size */
1139335640Shselasky	int c;
1140335640Shselasky	char dagname[DAGNAME_BUFSIZE];
1141335640Shselasky	int dagstream;
1142335640Shselasky	int dagfd;
1143335640Shselasky	dag_card_inf_t *inf;
1144335640Shselasky	char *description;
1145335640Shselasky	int stream, rxstreams;
1146335640Shselasky
1147335640Shselasky	/* Try all the DAGs 0-DAG_MAX_BOARDS */
1148335640Shselasky	for (c = 0; c < DAG_MAX_BOARDS; c++) {
1149335640Shselasky		pcap_snprintf(name, 12, "dag%d", c);
1150335640Shselasky		if (-1 == dag_parse_name(name, dagname, DAGNAME_BUFSIZE, &dagstream))
1151335640Shselasky		{
1152335640Shselasky			(void) pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
1153335640Shselasky			    "dag: device name %s can't be parsed", name);
1154335640Shselasky			return (-1);
1155335640Shselasky		}
1156335640Shselasky		if ( (dagfd = dag_open(dagname)) >= 0 ) {
1157335640Shselasky			description = NULL;
1158335640Shselasky			if ((inf = dag_pciinfo(dagfd)))
1159335640Shselasky				description = dag_device_name(inf->device_code, 1);
1160335640Shselasky			/*
1161335640Shselasky			 * XXX - is there a way to determine whether
1162335640Shselasky			 * the card is plugged into a network or not?
1163335640Shselasky			 * If so, we should check that and set
1164335640Shselasky			 * PCAP_IF_CONNECTION_STATUS_CONNECTED or
1165335640Shselasky			 * PCAP_IF_CONNECTION_STATUS_DISCONNECTED.
1166335640Shselasky			 *
1167335640Shselasky			 * Also, are there notions of "up" and "running"?
1168335640Shselasky			 */
1169335640Shselasky			if (add_dev(devlistp, name, 0, description, errbuf) == NULL) {
1170335640Shselasky				/*
1171335640Shselasky				 * Failure.
1172335640Shselasky				 */
1173335640Shselasky				return (-1);
1174335640Shselasky			}
1175335640Shselasky			rxstreams = dag_rx_get_stream_count(dagfd);
1176335640Shselasky			for(stream=0;stream<DAG_STREAM_MAX;stream+=2) {
1177356341Scy				if (0 == dag_attach_stream64(dagfd, stream, 0, 0)) {
1178335640Shselasky					dag_detach_stream(dagfd, stream);
1179335640Shselasky
1180335640Shselasky					pcap_snprintf(name,  10, "dag%d:%d", c, stream);
1181335640Shselasky					if (add_dev(devlistp, name, 0, description, errbuf) == NULL) {
1182335640Shselasky						/*
1183335640Shselasky						 * Failure.
1184335640Shselasky						 */
1185335640Shselasky						return (-1);
1186335640Shselasky					}
1187335640Shselasky
1188335640Shselasky					rxstreams--;
1189335640Shselasky					if(rxstreams <= 0) {
1190335640Shselasky						break;
1191335640Shselasky					}
1192335640Shselasky				}
1193335640Shselasky			}
1194335640Shselasky			dag_close(dagfd);
1195335640Shselasky		}
1196335640Shselasky
1197335640Shselasky	}
1198335640Shselasky	return (0);
1199335640Shselasky}
1200335640Shselasky
1201335640Shselasky/*
1202335640Shselasky * Installs the given bpf filter program in the given pcap structure.  There is
1203335640Shselasky * no attempt to store the filter in kernel memory as that is not supported
1204335640Shselasky * with DAG cards.
1205335640Shselasky */
1206335640Shselaskystatic int
1207335640Shselaskydag_setfilter(pcap_t *p, struct bpf_program *fp)
1208335640Shselasky{
1209335640Shselasky	if (!p)
1210335640Shselasky		return -1;
1211335640Shselasky	if (!fp) {
1212335640Shselasky		strncpy(p->errbuf, "setfilter: No filter specified",
1213335640Shselasky			sizeof(p->errbuf));
1214335640Shselasky		return -1;
1215335640Shselasky	}
1216335640Shselasky
1217335640Shselasky	/* Make our private copy of the filter */
1218335640Shselasky
1219335640Shselasky	if (install_bpf_program(p, fp) < 0)
1220335640Shselasky		return -1;
1221335640Shselasky
1222335640Shselasky	return (0);
1223335640Shselasky}
1224335640Shselasky
1225335640Shselaskystatic int
1226335640Shselaskydag_set_datalink(pcap_t *p, int dlt)
1227335640Shselasky{
1228335640Shselasky	p->linktype = dlt;
1229335640Shselasky
1230335640Shselasky	return (0);
1231335640Shselasky}
1232335640Shselasky
1233335640Shselaskystatic int
1234335640Shselaskydag_setnonblock(pcap_t *p, int nonblock)
1235335640Shselasky{
1236335640Shselasky	struct pcap_dag *pd = p->priv;
1237335640Shselasky	dag_size_t mindata;
1238335640Shselasky	struct timeval maxwait;
1239335640Shselasky	struct timeval poll;
1240335640Shselasky
1241335640Shselasky	/*
1242335640Shselasky	 * Set non-blocking mode on the FD.
1243335640Shselasky	 * XXX - is that necessary?  If not, don't bother calling it,
1244335640Shselasky	 * and have a "dag_getnonblock()" function that looks at
1245335640Shselasky	 * "pd->dag_flags".
1246335640Shselasky	 */
1247335640Shselasky	if (pcap_setnonblock_fd(p, nonblock) < 0)
1248335640Shselasky		return (-1);
1249335640Shselasky
1250335640Shselasky	if (dag_get_stream_poll64(p->fd, pd->dag_stream,
1251335640Shselasky				&mindata, &maxwait, &poll) < 0) {
1252335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
1253335640Shselasky		    errno, "dag_get_stream_poll");
1254335640Shselasky		return -1;
1255335640Shselasky	}
1256335640Shselasky
1257335640Shselasky	/* Amount of data to collect in Bytes before calling callbacks.
1258335640Shselasky	 * Important for efficiency, but can introduce latency
1259335640Shselasky	 * at low packet rates if to_ms not set!
1260335640Shselasky	 */
1261335640Shselasky	if(nonblock)
1262335640Shselasky		mindata = 0;
1263335640Shselasky	else
1264335640Shselasky		mindata = 65536;
1265335640Shselasky
1266335640Shselasky	if (dag_set_stream_poll64(p->fd, pd->dag_stream,
1267335640Shselasky				mindata, &maxwait, &poll) < 0) {
1268335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
1269335640Shselasky		    errno, "dag_set_stream_poll");
1270335640Shselasky		return -1;
1271335640Shselasky	}
1272335640Shselasky
1273335640Shselasky	if (nonblock) {
1274335640Shselasky		pd->dag_flags |= DAGF_NONBLOCK;
1275335640Shselasky	} else {
1276335640Shselasky		pd->dag_flags &= ~DAGF_NONBLOCK;
1277335640Shselasky	}
1278335640Shselasky	return (0);
1279335640Shselasky}
1280335640Shselasky
1281335640Shselaskystatic int
1282335640Shselaskydag_get_datalink(pcap_t *p)
1283335640Shselasky{
1284335640Shselasky	struct pcap_dag *pd = p->priv;
1285335640Shselasky	int index=0, dlt_index=0;
1286335640Shselasky	uint8_t types[255];
1287335640Shselasky
1288335640Shselasky	memset(types, 0, 255);
1289335640Shselasky
1290335640Shselasky	if (p->dlt_list == NULL && (p->dlt_list = malloc(255*sizeof(*(p->dlt_list)))) == NULL) {
1291335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
1292335640Shselasky		    errno, "malloc");
1293335640Shselasky		return (-1);
1294335640Shselasky	}
1295335640Shselasky
1296335640Shselasky	p->linktype = 0;
1297335640Shselasky
1298335640Shselasky#ifdef HAVE_DAG_GET_STREAM_ERF_TYPES
1299335640Shselasky	/* Get list of possible ERF types for this card */
1300335640Shselasky	if (dag_get_stream_erf_types(p->fd, pd->dag_stream, types, 255) < 0) {
1301335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
1302335640Shselasky		    errno, "dag_get_stream_erf_types");
1303335640Shselasky		return (-1);
1304335640Shselasky	}
1305335640Shselasky
1306335640Shselasky	while (types[index]) {
1307335640Shselasky
1308335640Shselasky#elif defined HAVE_DAG_GET_ERF_TYPES
1309335640Shselasky	/* Get list of possible ERF types for this card */
1310335640Shselasky	if (dag_get_erf_types(p->fd, types, 255) < 0) {
1311335640Shselasky		pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
1312335640Shselasky		    errno, "dag_get_erf_types");
1313335640Shselasky		return (-1);
1314335640Shselasky	}
1315335640Shselasky
1316335640Shselasky	while (types[index]) {
1317335640Shselasky#else
1318335640Shselasky	/* Check the type through a dagapi call. */
1319335640Shselasky	types[index] = dag_linktype(p->fd);
1320335640Shselasky
1321335640Shselasky	{
1322335640Shselasky#endif
1323335640Shselasky		switch((types[index] & 0x7f)) {
1324335640Shselasky
1325335640Shselasky		case ERF_TYPE_HDLC_POS:
1326335640Shselasky		case ERF_TYPE_COLOR_HDLC_POS:
1327335640Shselasky		case ERF_TYPE_DSM_COLOR_HDLC_POS:
1328335640Shselasky		case ERF_TYPE_COLOR_HASH_POS:
1329335640Shselasky
1330335640Shselasky			if (p->dlt_list != NULL) {
1331335640Shselasky				p->dlt_list[dlt_index++] = DLT_CHDLC;
1332335640Shselasky				p->dlt_list[dlt_index++] = DLT_PPP_SERIAL;
1333335640Shselasky				p->dlt_list[dlt_index++] = DLT_FRELAY;
1334335640Shselasky			}
1335335640Shselasky			if(!p->linktype)
1336335640Shselasky				p->linktype = DLT_CHDLC;
1337335640Shselasky			break;
1338335640Shselasky
1339335640Shselasky		case ERF_TYPE_ETH:
1340335640Shselasky		case ERF_TYPE_COLOR_ETH:
1341335640Shselasky		case ERF_TYPE_DSM_COLOR_ETH:
1342335640Shselasky		case ERF_TYPE_COLOR_HASH_ETH:
1343335640Shselasky			/*
1344335640Shselasky			 * This is (presumably) a real Ethernet capture; give it a
1345335640Shselasky			 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
1346335640Shselasky			 * that an application can let you choose it, in case you're
1347335640Shselasky			 * capturing DOCSIS traffic that a Cisco Cable Modem
1348335640Shselasky			 * Termination System is putting out onto an Ethernet (it
1349335640Shselasky			 * doesn't put an Ethernet header onto the wire, it puts raw
1350335640Shselasky			 * DOCSIS frames out on the wire inside the low-level
1351335640Shselasky			 * Ethernet framing).
1352335640Shselasky			 */
1353335640Shselasky			if (p->dlt_list != NULL) {
1354335640Shselasky				p->dlt_list[dlt_index++] = DLT_EN10MB;
1355335640Shselasky				p->dlt_list[dlt_index++] = DLT_DOCSIS;
1356335640Shselasky			}
1357335640Shselasky			if(!p->linktype)
1358335640Shselasky				p->linktype = DLT_EN10MB;
1359335640Shselasky			break;
1360335640Shselasky
1361335640Shselasky		case ERF_TYPE_ATM:
1362335640Shselasky		case ERF_TYPE_AAL5:
1363335640Shselasky		case ERF_TYPE_MC_ATM:
1364335640Shselasky		case ERF_TYPE_MC_AAL5:
1365335640Shselasky			if (p->dlt_list != NULL) {
1366335640Shselasky				p->dlt_list[dlt_index++] = DLT_ATM_RFC1483;
1367335640Shselasky				p->dlt_list[dlt_index++] = DLT_SUNATM;
1368335640Shselasky			}
1369335640Shselasky			if(!p->linktype)
1370335640Shselasky				p->linktype = DLT_ATM_RFC1483;
1371335640Shselasky			break;
1372335640Shselasky
1373335640Shselasky		case ERF_TYPE_COLOR_MC_HDLC_POS:
1374335640Shselasky		case ERF_TYPE_MC_HDLC:
1375335640Shselasky			if (p->dlt_list != NULL) {
1376335640Shselasky				p->dlt_list[dlt_index++] = DLT_CHDLC;
1377335640Shselasky				p->dlt_list[dlt_index++] = DLT_PPP_SERIAL;
1378335640Shselasky				p->dlt_list[dlt_index++] = DLT_FRELAY;
1379335640Shselasky				p->dlt_list[dlt_index++] = DLT_MTP2;
1380335640Shselasky				p->dlt_list[dlt_index++] = DLT_MTP2_WITH_PHDR;
1381335640Shselasky				p->dlt_list[dlt_index++] = DLT_LAPD;
1382335640Shselasky			}
1383335640Shselasky			if(!p->linktype)
1384335640Shselasky				p->linktype = DLT_CHDLC;
1385335640Shselasky			break;
1386335640Shselasky
1387335640Shselasky		case ERF_TYPE_IPV4:
1388335640Shselasky			if (p->dlt_list != NULL) {
1389335640Shselasky				p->dlt_list[dlt_index++] = DLT_RAW;
1390335640Shselasky				p->dlt_list[dlt_index++] = DLT_IPV4;
1391335640Shselasky			}
1392335640Shselasky			if(!p->linktype)
1393335640Shselasky				p->linktype = DLT_RAW;
1394335640Shselasky			break;
1395335640Shselasky
1396335640Shselasky		case ERF_TYPE_IPV6:
1397335640Shselasky			if (p->dlt_list != NULL) {
1398335640Shselasky				p->dlt_list[dlt_index++] = DLT_RAW;
1399335640Shselasky				p->dlt_list[dlt_index++] = DLT_IPV6;
1400335640Shselasky			}
1401335640Shselasky			if(!p->linktype)
1402335640Shselasky				p->linktype = DLT_RAW;
1403335640Shselasky			break;
1404335640Shselasky
1405335640Shselasky		case ERF_TYPE_LEGACY:
1406335640Shselasky		case ERF_TYPE_MC_RAW:
1407335640Shselasky		case ERF_TYPE_MC_RAW_CHANNEL:
1408335640Shselasky		case ERF_TYPE_IP_COUNTER:
1409335640Shselasky		case ERF_TYPE_TCP_FLOW_COUNTER:
1410335640Shselasky		case ERF_TYPE_INFINIBAND:
1411335640Shselasky		case ERF_TYPE_RAW_LINK:
1412335640Shselasky		case ERF_TYPE_INFINIBAND_LINK:
1413335640Shselasky		case ERF_TYPE_META:
1414335640Shselasky		default:
1415335640Shselasky			/* Libpcap cannot deal with these types yet */
1416335640Shselasky			/* Add no 'native' DLTs, but still covered by DLT_ERF */
1417335640Shselasky			break;
1418335640Shselasky
1419335640Shselasky		} /* switch */
1420335640Shselasky		index++;
1421335640Shselasky	}
1422335640Shselasky
1423335640Shselasky	p->dlt_list[dlt_index++] = DLT_ERF;
1424335640Shselasky
1425335640Shselasky	p->dlt_count = dlt_index;
1426335640Shselasky
1427335640Shselasky	if(!p->linktype)
1428335640Shselasky		p->linktype = DLT_ERF;
1429335640Shselasky
1430335640Shselasky	return p->linktype;
1431335640Shselasky}
1432335640Shselasky
1433335640Shselasky#ifdef DAG_ONLY
1434335640Shselasky/*
1435335640Shselasky * This libpcap build supports only DAG cards, not regular network
1436335640Shselasky * interfaces.
1437335640Shselasky */
1438335640Shselasky
1439335640Shselasky/*
1440335640Shselasky * There are no regular interfaces, just DAG interfaces.
1441335640Shselasky */
1442335640Shselaskyint
1443335640Shselaskypcap_platform_finddevs(pcap_if_list_t *devlistp _U_, char *errbuf)
1444335640Shselasky{
1445335640Shselasky	return (0);
1446335640Shselasky}
1447335640Shselasky
1448335640Shselasky/*
1449335640Shselasky * Attempts to open a regular interface fail.
1450335640Shselasky */
1451335640Shselaskypcap_t *
1452335640Shselaskypcap_create_interface(const char *device, char *errbuf)
1453335640Shselasky{
1454335640Shselasky	pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
1455335640Shselasky	    "This version of libpcap only supports DAG cards");
1456335640Shselasky	return NULL;
1457335640Shselasky}
1458335640Shselasky
1459335640Shselasky/*
1460335640Shselasky * Libpcap version string.
1461335640Shselasky */
1462335640Shselaskyconst char *
1463335640Shselaskypcap_lib_version(void)
1464335640Shselasky{
1465335640Shselasky	return (PCAP_VERSION_STRING " (DAG-only)");
1466335640Shselasky}
1467335640Shselasky#endif
1468