pcap-dag.c revision 147894
1231990Smp/*
259243Sobrien * pcap-dag.c: Packet capture interface for Endace DAG card.
359243Sobrien *
459243Sobrien * The functionality of this code attempts to mimic that of pcap-linux as much
559243Sobrien * as possible.  This code is compiled in several different ways depending on
659243Sobrien * whether DAG_ONLY and HAVE_DAG_API are defined.  If HAVE_DAG_API is not
759243Sobrien * defined it should not get compiled in, otherwise if DAG_ONLY is defined then
859243Sobrien * the 'dag_' function calls are renamed to 'pcap_' equivalents.  If DAG_ONLY
959243Sobrien * is not defined then nothing is altered - the dag_ functions will be
1059243Sobrien * called as required from their pcap-linux/bpf equivalents.
1159243Sobrien *
1259243Sobrien * Authors: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com)
1359243Sobrien * Modifications: Jesper Peterson, Koryn Grant <support@endace.com>
1459243Sobrien */
1559243Sobrien
1659243Sobrien#ifndef lint
17100616Smpstatic const char rcsid[] _U_ =
1859243Sobrien	"@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.21.2.1 2005/05/03 18:54:35 guy Exp $ (LBL)";
1959243Sobrien#endif
2059243Sobrien
2159243Sobrien#ifdef HAVE_CONFIG_H
2259243Sobrien#include "config.h"
2359243Sobrien#endif
2459243Sobrien
2559243Sobrien#include <sys/param.h>			/* optionally get BSD define */
2659243Sobrien
2759243Sobrien#include <stdlib.h>
2859243Sobrien#include <string.h>
2959243Sobrien#include <errno.h>
3059243Sobrien
3159243Sobrien#include "pcap-int.h"
3259243Sobrien
3359243Sobrien#include <ctype.h>
3459243Sobrien#include <netinet/in.h>
35231990Smp#include <sys/mman.h>
3659243Sobrien#include <sys/socket.h>
3759243Sobrien#include <sys/types.h>
3859243Sobrien#include <unistd.h>
3959243Sobrien
4059243Sobrienstruct mbuf;		/* Squelch compiler warnings on some platforms for */
4159243Sobrienstruct rtentry;		/* declarations in <net/if.h> */
4259243Sobrien#include <net/if.h>
4359243Sobrien
4459243Sobrien#include "dagnew.h"
4559243Sobrien#include "dagapi.h"
46231990Smp
4759243Sobrien#define MIN_DAG_SNAPLEN		12
4859243Sobrien#define MAX_DAG_SNAPLEN		2040
4959243Sobrien#define ATM_CELL_SIZE		52
50184072Sru#define ATM_HDR_SIZE		4
5159243Sobrien
5259243Sobrien/* SunATM pseudo header */
5359243Sobrienstruct sunatm_hdr {
5459243Sobrien	unsigned char	flags;		/* destination and traffic type */
5559243Sobrien	unsigned char	vpi;		/* VPI */
5659243Sobrien	unsigned short	vci;		/* VCI */
5759243Sobrien};
5859243Sobrien
5959243Sobrientypedef struct pcap_dag_node {
6059243Sobrien	struct pcap_dag_node *next;
6159243Sobrien	pcap_t *p;
6259243Sobrien	pid_t pid;
6359243Sobrien} pcap_dag_node_t;
64231990Smp
6559243Sobrienstatic pcap_dag_node_t *pcap_dags = NULL;
6659243Sobrienstatic int atexit_handler_installed = 0;
6759243Sobrienstatic const unsigned short endian_test_word = 0x0100;
6859243Sobrien
6959243Sobrien#define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word))
7059243Sobrien
7159243Sobrien/*
72231990Smp * Swap byte ordering of unsigned long long timestamp on a big endian
7359243Sobrien * machine.
7459243Sobrien */
7559243Sobrien#define SWAP_TS(ull)  ((ull & 0xff00000000000000LL) >> 56) | \
7659243Sobrien                      ((ull & 0x00ff000000000000LL) >> 40) | \
7759243Sobrien                      ((ull & 0x0000ff0000000000LL) >> 24) | \
7859243Sobrien                      ((ull & 0x000000ff00000000LL) >> 8)  | \
7959243Sobrien                      ((ull & 0x00000000ff000000LL) << 8)  | \
8059243Sobrien                      ((ull & 0x0000000000ff0000LL) << 24) | \
8159243Sobrien                      ((ull & 0x000000000000ff00LL) << 40) | \
8259243Sobrien                      ((ull & 0x00000000000000ffLL) << 56)
8359243Sobrien
8459243Sobrien
8559243Sobrien#ifdef DAG_ONLY
8659243Sobrien/* This code is required when compiling for a DAG device only. */
8759243Sobrien#include "pcap-dag.h"
8859243Sobrien
8959243Sobrien/* Replace dag function names with pcap equivalent. */
90145479Smp#define dag_open_live pcap_open_live
91145479Smp#define dag_platform_finddevs pcap_platform_finddevs
9259243Sobrien#endif /* DAG_ONLY */
9359243Sobrien
9459243Sobrienstatic int dag_setfilter(pcap_t *p, struct bpf_program *fp);
9559243Sobrienstatic int dag_stats(pcap_t *p, struct pcap_stat *ps);
9659243Sobrienstatic int dag_set_datalink(pcap_t *p, int dlt);
9759243Sobrienstatic int dag_get_datalink(pcap_t *p);
9859243Sobrienstatic int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf);
9959243Sobrien
10059243Sobrienstatic void
10159243Sobriendelete_pcap_dag(pcap_t *p)
10259243Sobrien{
10359243Sobrien	pcap_dag_node_t *curr = NULL, *prev = NULL;
10459243Sobrien
10559243Sobrien	for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) {
10659243Sobrien		/* empty */
10759243Sobrien	}
10859243Sobrien
10959243Sobrien	if (curr != NULL && curr->p == p) {
11059243Sobrien		if (prev != NULL) {
11159243Sobrien			prev->next = curr->next;
11259243Sobrien		} else {
11359243Sobrien			pcap_dags = curr->next;
11459243Sobrien		}
11559243Sobrien	}
11659243Sobrien}
11759243Sobrien
11859243Sobrien/*
11969408Sache * Performs a graceful shutdown of the DAG card, frees dynamic memory held
12069408Sache * in the pcap_t structure, and closes the file descriptor for the DAG card.
121100616Smp */
12269408Sache
12359243Sobrienstatic void
12459243Sobriendag_platform_close(pcap_t *p)
12559243Sobrien{
12659243Sobrien
127131962Smp#ifdef linux
128131962Smp	if (p != NULL && p->md.device != NULL) {
129131962Smp		if(dag_stop(p->fd) < 0)
13059243Sobrien			fprintf(stderr,"dag_stop %s: %s\n", p->md.device, strerror(errno));
131131962Smp		if(dag_close(p->fd) < 0)
132145479Smp			fprintf(stderr,"dag_close %s: %s\n", p->md.device, strerror(errno));
133145479Smp
134145479Smp		free(p->md.device);
135145479Smp	}
136145479Smp#else
137145479Smp	if (p != NULL) {
13859243Sobrien		if(dag_stop(p->fd) < 0)
13959243Sobrien			fprintf(stderr,"dag_stop: %s\n", strerror(errno));
14059243Sobrien		if(dag_close(p->fd) < 0)
14159243Sobrien			fprintf(stderr,"dag_close: %s\n", strerror(errno));
14259243Sobrien	}
143131962Smp#endif
14459415Sobrien	delete_pcap_dag(p);
14590446Smp	/* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */
14659243Sobrien}
147131962Smp
14859415Sobrienstatic void
14959415Sobrienatexit_handler(void)
15059243Sobrien{
15159415Sobrien	while (pcap_dags != NULL) {
15259415Sobrien		if (pcap_dags->pid == getpid()) {
15359243Sobrien			dag_platform_close(pcap_dags->p);
15459415Sobrien		} else {
15559415Sobrien			delete_pcap_dag(pcap_dags->p);
15659243Sobrien		}
15759415Sobrien	}
15859415Sobrien}
15959243Sobrien
16059243Sobrienstatic int
16159243Sobriennew_pcap_dag(pcap_t *p)
16259243Sobrien{
16383098Smp	pcap_dag_node_t *node = NULL;
16483098Smp
16590446Smp	if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) {
16690446Smp		return -1;
167231990Smp	}
168131962Smp
169131962Smp	if (!atexit_handler_installed) {
170131962Smp		atexit(atexit_handler);
171131962Smp		atexit_handler_installed = 1;
172131962Smp	}
173131962Smp
174131962Smp	node->next = pcap_dags;
175131962Smp	node->p = p;
176131962Smp	node->pid = getpid();
177131962Smp
178131962Smp	pcap_dags = node;
179131962Smp
180131962Smp	return 0;
181131962Smp}
182131962Smp
183195609Smp/*
18490446Smp *  Read at most max_packets from the capture stream and call the callback
18569408Sache *  for each of them. Returns the number of packets handled, -1 if an
18690446Smp *  error occured, or -2 if we were told to break out of the loop.
18790446Smp */
18890446Smpstatic int
18990446Smpdag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
19090446Smp{
19190446Smp	unsigned int processed = 0;
19290446Smp	int flags = p->md.dag_offset_flags;
19369408Sache	unsigned int nonblocking = flags & DAGF_NONBLOCK;
19469408Sache
19590446Smp	for (;;)
19690446Smp	{
19790446Smp		/* Get the next bufferful of packets (if necessary). */
19890446Smp		while (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size) {
19959243Sobrien
20059415Sobrien			/*
20159415Sobrien			 * Has "pcap_breakloop()" been called?
20290446Smp			 */
20359415Sobrien			if (p->break_loop) {
20459415Sobrien				/*
20590446Smp				 * Yes - clear the flag that indicates that
20659243Sobrien				 * it has, and return -2 to indicate that
20759243Sobrien				 * we were told to break out of the loop.
20883098Smp				 */
20959243Sobrien				p->break_loop = 0;
21059415Sobrien				return -2;
21159415Sobrien			}
21290446Smp
21359415Sobrien			p->md.dag_mem_top = dag_offset(p->fd, &(p->md.dag_mem_bottom), flags);
21459415Sobrien			if (nonblocking && (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size))
21590446Smp			{
21659243Sobrien				/* Pcap is configured to process only available packets, and there aren't any. */
21759243Sobrien				return 0;
21883098Smp			}
21959243Sobrien		}
22059415Sobrien
22159415Sobrien		/* Process the packets. */
22290446Smp		while (p->md.dag_mem_top - p->md.dag_mem_bottom >= dag_record_size) {
22359415Sobrien
22459415Sobrien			unsigned short packet_len = 0;
22590446Smp			int caplen = 0;
22659243Sobrien			struct pcap_pkthdr	pcap_header;
22759243Sobrien
22883098Smp			dag_record_t *header = (dag_record_t *)(p->md.dag_mem_base + p->md.dag_mem_bottom);
22959243Sobrien			u_char *dp = ((u_char *)header) + dag_record_size;
23059415Sobrien			unsigned short rlen;
23159415Sobrien
23290446Smp			/*
23359415Sobrien			 * Has "pcap_breakloop()" been called?
23459415Sobrien			 */
23590446Smp			if (p->break_loop) {
23659243Sobrien				/*
23759243Sobrien				 * Yes - clear the flag that indicates that
23883098Smp				 * it has, and return -2 to indicate that
23959243Sobrien				 * we were told to break out of the loop.
24059243Sobrien				 */
24159243Sobrien				p->break_loop = 0;
24259243Sobrien				return -2;
24359243Sobrien			}
24459243Sobrien
24559243Sobrien				rlen = ntohs(header->rlen);
24659243Sobrien			if (rlen < dag_record_size)
24759243Sobrien			{
24859243Sobrien				strncpy(p->errbuf, "dag_read: record too small", PCAP_ERRBUF_SIZE);
24959243Sobrien				return -1;
25059243Sobrien			}
25159243Sobrien			p->md.dag_mem_bottom += rlen;
25259243Sobrien
25359243Sobrien			switch(header->type) {
25459243Sobrien			case TYPE_AAL5:
255231990Smp			case TYPE_ATM:
25659243Sobrien				if (header->type == TYPE_AAL5) {
25759243Sobrien						packet_len = ntohs(header->wlen);
25859243Sobrien					caplen = rlen - dag_record_size;
25959243Sobrien				} else {
26059243Sobrien					caplen = packet_len = ATM_CELL_SIZE;
26159243Sobrien				}
26259243Sobrien				if (p->linktype == DLT_SUNATM) {
26383098Smp					struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp;
26459243Sobrien					unsigned long rawatm;
26559243Sobrien
26659243Sobrien						rawatm = ntohl(*((unsigned long *)dp));
26759243Sobrien						sunatm->vci = htons((rawatm >>  4) & 0xffff);
26859243Sobrien					sunatm->vpi = (rawatm >> 20) & 0x00ff;
26959243Sobrien					sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) |
27059243Sobrien						((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 :
27159243Sobrien						((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 :
27259243Sobrien						((dp[ATM_HDR_SIZE] == 0xaa &&
27359243Sobrien							dp[ATM_HDR_SIZE+1] == 0xaa &&
27459243Sobrien							dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1)));
27559243Sobrien
27659243Sobrien				} else {
27759243Sobrien					packet_len -= ATM_HDR_SIZE;
27859243Sobrien					caplen -= ATM_HDR_SIZE;
27959243Sobrien					dp += ATM_HDR_SIZE;
28059243Sobrien				}
28159243Sobrien				break;
28259243Sobrien
28359243Sobrien			case TYPE_ETH:
28459243Sobrien					packet_len = ntohs(header->wlen);
28559243Sobrien				packet_len -= (p->md.dag_fcs_bits >> 3);
28659243Sobrien				caplen = rlen - dag_record_size - 2;
28759243Sobrien				if (caplen > packet_len) {
28859243Sobrien					caplen = packet_len;
28959243Sobrien				}
29059243Sobrien				dp += 2;
29159243Sobrien				break;
29259243Sobrien
29359243Sobrien			case TYPE_HDLC_POS:
29459243Sobrien					packet_len = ntohs(header->wlen);
29559243Sobrien				packet_len -= (p->md.dag_fcs_bits >> 3);
29659243Sobrien				caplen = rlen - dag_record_size;
29759243Sobrien				if (caplen > packet_len) {
29859243Sobrien					caplen = packet_len;
29959243Sobrien				}
30059243Sobrien				break;
30159243Sobrien			}
30259243Sobrien
30359243Sobrien			if (caplen > p->snapshot)
30459243Sobrien				caplen = p->snapshot;
30559243Sobrien
30659243Sobrien			/* Count lost packets. */
30759243Sobrien			if (header->lctr) {
30859243Sobrien				if (p->md.stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) {
30959243Sobrien					p->md.stat.ps_drop = UINT_MAX;
310231990Smp				} else {
311231990Smp					p->md.stat.ps_drop += ntohs(header->lctr);
31259243Sobrien				}
31359243Sobrien			}
31459243Sobrien
31559243Sobrien			/* Run the packet filter if there is one. */
31659243Sobrien			if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
31759243Sobrien
31859243Sobrien				/* convert between timestamp formats */
31959243Sobrien				register unsigned long long ts;
32059243Sobrien
32159243Sobrien				if (IS_BIGENDIAN()) {
32259243Sobrien					ts = SWAP_TS(header->ts);
32359243Sobrien				} else {
32459243Sobrien					ts = header->ts;
32559243Sobrien				}
32659243Sobrien
32759243Sobrien				pcap_header.ts.tv_sec = ts >> 32;
32859243Sobrien				ts = (ts & 0xffffffffULL) * 1000000;
32959243Sobrien				ts += 0x80000000; /* rounding */
33059243Sobrien				pcap_header.ts.tv_usec = ts >> 32;
33159243Sobrien				if (pcap_header.ts.tv_usec >= 1000000) {
33259243Sobrien					pcap_header.ts.tv_usec -= 1000000;
33359243Sobrien					pcap_header.ts.tv_sec++;
33459243Sobrien				}
33559243Sobrien
33659243Sobrien				/* Fill in our own header data */
33759243Sobrien				pcap_header.caplen = caplen;
33859243Sobrien				pcap_header.len = packet_len;
33959243Sobrien
34059243Sobrien				/* Count the packet. */
34159243Sobrien				p->md.stat.ps_recv++;
34259243Sobrien
34359243Sobrien				/* Call the user supplied callback function */
344100616Smp				callback(user, &pcap_header, dp);
345100616Smp
346100616Smp				/* Only count packets that pass the filter, for consistency with standard Linux behaviour. */
34759243Sobrien				processed++;
34859243Sobrien				if (processed == cnt)
34959243Sobrien				{
35059243Sobrien					/* Reached the user-specified limit. */
35159243Sobrien					return cnt;
35259243Sobrien				}
35359243Sobrien			}
35459243Sobrien		}
35559243Sobrien
35659243Sobrien		if (nonblocking || processed)
35759243Sobrien		{
35859243Sobrien			return processed;
359195609Smp		}
360195609Smp	}
36159243Sobrien
36259243Sobrien	return processed;
36359243Sobrien}
36459243Sobrien
36559243Sobrienstatic int
36659243Sobriendag_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
36759243Sobrien{
36859243Sobrien	strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards",
36959243Sobrien	    PCAP_ERRBUF_SIZE);
37059243Sobrien	return (-1);
37159243Sobrien}
37259243Sobrien
37359243Sobrien/*
37459243Sobrien *  Get a handle for a live capture from the given DAG device.  Passing a NULL
37559243Sobrien *  device will result in a failure.  The promisc flag is ignored because DAG
37659243Sobrien *  cards are always promiscuous.  The to_ms parameter is also ignored as it is
37759243Sobrien *  not supported in hardware.
37859243Sobrien *
37959243Sobrien *  See also pcap(3).
38059243Sobrien */
38159243Sobrienpcap_t *
38259243Sobriendag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf)
38359243Sobrien{
38459243Sobrien	char conf[30]; /* dag configure string */
385231990Smp	pcap_t *handle;
38659243Sobrien	char *s;
38759243Sobrien	int n;
38859243Sobrien	daginf_t* daginf;
389231990Smp
39059243Sobrien	if (device == NULL) {
391131962Smp		snprintf(ebuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno));
39259243Sobrien		return NULL;
39359243Sobrien	}
39459243Sobrien	/* Allocate a handle for this session. */
39559243Sobrien
39659243Sobrien	handle = malloc(sizeof(*handle));
397231990Smp	if (handle == NULL) {
39859243Sobrien		snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc %s: %s", device, pcap_strerror(errno));
39959243Sobrien		return NULL;
40059243Sobrien	}
40159243Sobrien
40259243Sobrien	/* Initialize some components of the pcap structure. */
40359243Sobrien
40459243Sobrien	memset(handle, 0, sizeof(*handle));
40559243Sobrien
406167465Smp	if (strstr(device, "/dev") == NULL) {
40759243Sobrien		char * newDev = (char *)malloc(strlen(device) + 6);
40859243Sobrien		newDev[0] = '\0';
40959243Sobrien		strcat(newDev, "/dev/");
41059243Sobrien		strcat(newDev,device);
41159243Sobrien		device = newDev;
41259243Sobrien	} else {
41359243Sobrien		device = strdup(device);
41459243Sobrien	}
41559243Sobrien
41659243Sobrien	if (device == NULL) {
41759243Sobrien		snprintf(ebuf, PCAP_ERRBUF_SIZE, "str_dup: %s\n", pcap_strerror(errno));
41859243Sobrien		goto fail;
41959243Sobrien	}
42059243Sobrien
42159243Sobrien	/* setup device parameters */
42259243Sobrien	if((handle->fd = dag_open((char *)device)) < 0) {
42359243Sobrien		snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno));
42459243Sobrien		goto fail;
42559243Sobrien	}
42659243Sobrien
42759243Sobrien	/* set the card snap length to the specified snaplen parameter */
42859243Sobrien	if (snaplen == 0 || snaplen > MAX_DAG_SNAPLEN) {
42959243Sobrien		snaplen = MAX_DAG_SNAPLEN;
43059243Sobrien	} else if (snaplen < MIN_DAG_SNAPLEN) {
431167465Smp		snaplen = MIN_DAG_SNAPLEN;
43259243Sobrien	}
43359243Sobrien	/* snap len has to be a multiple of 4 */
43459243Sobrien	snprintf(conf, 30, "varlen slen=%d", (snaplen + 3) & ~3);
43583098Smp
43683098Smp	if(dag_configure(handle->fd, conf) < 0) {
43759243Sobrien		snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno));
43859243Sobrien		goto fail;
43959243Sobrien	}
440131962Smp
44159243Sobrien	if((handle->md.dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) {
44259243Sobrien		snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno));
44359243Sobrien		goto fail;
44459243Sobrien	}
44559243Sobrien
44659243Sobrien	if(dag_start(handle->fd) < 0) {
44759243Sobrien		snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno));
44859243Sobrien		goto fail;
44959243Sobrien	}
45059243Sobrien
45159243Sobrien	/*
45259243Sobrien	 * Important! You have to ensure bottom is properly
45359243Sobrien	 * initialized to zero on startup, it won't give you
45459243Sobrien	 * a compiler warning if you make this mistake!
45559243Sobrien	 */
45659243Sobrien	handle->md.dag_mem_bottom = 0;
45759243Sobrien	handle->md.dag_mem_top = 0;
45859243Sobrien	handle->md.dag_fcs_bits = 32;
45959243Sobrien
460167465Smp	/* Query the card first for special cases. */
461195609Smp	daginf = dag_info(handle->fd);
462195609Smp	if ((0x4200 == daginf->device_code) || (0x4230 == daginf->device_code))
463195609Smp	{
464167465Smp		/* DAG 4.2S and 4.23S already strip the FCS.  Stripping the final word again truncates the packet. */
465195609Smp		handle->md.dag_fcs_bits = 0;
466195609Smp	}
467167465Smp
46859243Sobrien	/* Then allow an environment variable to override. */
46959243Sobrien	if ((s = getenv("ERF_FCS_BITS")) != NULL) {
47059243Sobrien		if ((n = atoi(s)) == 0 || n == 16|| n == 32) {
47159243Sobrien			handle->md.dag_fcs_bits = n;
47259243Sobrien		} else {
47359243Sobrien			snprintf(ebuf, PCAP_ERRBUF_SIZE,
47459243Sobrien				"pcap_open_live %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n);
47559243Sobrien			goto fail;
47659243Sobrien		}
47759243Sobrien	}
47859243Sobrien
47959243Sobrien	handle->snapshot	= snaplen;
48069408Sache	/*handle->md.timeout	= to_ms; */
48159243Sobrien
48259243Sobrien	handle->linktype = -1;
48359243Sobrien	if (dag_get_datalink(handle) < 0) {
484145479Smp		strcpy(ebuf, handle->errbuf);
48559243Sobrien		goto fail;
48659243Sobrien	}
48759243Sobrien
48883098Smp	handle->bufsize = 0;
48983098Smp
49083098Smp	if (new_pcap_dag(handle) < 0) {
49183098Smp		snprintf(ebuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno));
49283098Smp		goto fail;
49359243Sobrien	}
49459243Sobrien
49559243Sobrien	/*
49659243Sobrien	 * "select()" and "poll()" don't (yet) work on DAG device descriptors.
49759243Sobrien	 */
49859243Sobrien	handle->selectable_fd = -1;
49959243Sobrien
50059243Sobrien#ifdef linux
50159243Sobrien	handle->md.device = (char *)device;
50269408Sache#else
50359243Sobrien	free((char *)device);
50459243Sobrien	device = NULL;
50559243Sobrien#endif
50659243Sobrien
50783098Smp	handle->read_op = dag_read;
50883098Smp	handle->inject_op = dag_inject;
50983098Smp	handle->setfilter_op = dag_setfilter;
510100616Smp	handle->setdirection_op = NULL; /* Not implemented.*/
511145479Smp	handle->set_datalink_op = dag_set_datalink;
512145479Smp	handle->getnonblock_op = pcap_getnonblock_fd;
513195609Smp	handle->setnonblock_op = dag_setnonblock;
514195609Smp	handle->stats_op = dag_stats;
515231990Smp	handle->close_op = dag_platform_close;
516231990Smp
517231990Smp	return handle;
518231990Smp
519fail:
520	if (device != NULL) {
521		free((char *)device);
522	}
523	if (handle != NULL) {
524		/*
525		 * Get rid of any link-layer type list we allocated.
526		 */
527		if (handle->dlt_list != NULL) {
528			free(handle->dlt_list);
529		}
530		free(handle);
531	}
532
533	return NULL;
534}
535
536static int
537dag_stats(pcap_t *p, struct pcap_stat *ps) {
538	/* This needs to be filled out correctly.  Hopefully a dagapi call will
539		 provide all necessary information.
540	*/
541	/*p->md.stat.ps_recv = 0;*/
542	/*p->md.stat.ps_drop = 0;*/
543
544	*ps = p->md.stat;
545
546	return 0;
547}
548
549/*
550 * Get from "/proc/dag" all interfaces listed there; if they're
551 * already in the list of interfaces we have, that won't add another
552 * instance, but if they're not, that'll add them.
553 *
554 * We don't bother getting any addresses for them.
555 *
556 * We also don't fail if we couldn't open "/proc/dag"; we just leave
557 * the list of interfaces as is.
558 */
559int
560dag_platform_finddevs(pcap_if_t **devlistp, char *errbuf)
561{
562	FILE *proc_dag_f;
563	char linebuf[512];
564	int linenum;
565	unsigned char *p;
566	char name[512];	/* XXX - pick a size */
567	char *q;
568	int ret = 0;
569
570	/* Quick exit if /proc/dag not readable */
571	proc_dag_f = fopen("/proc/dag", "r");
572	if (proc_dag_f == NULL)
573	{
574		int i;
575		char dev[16] = "dagx";
576
577		for (i = '0'; ret == 0 && i <= '9'; i++) {
578			dev[3] = i;
579			if (pcap_add_if(devlistp, dev, 0, NULL, errbuf) == -1) {
580				/*
581				 * Failure.
582				 */
583				ret = -1;
584			}
585		}
586
587		return (ret);
588	}
589
590	for (linenum = 1; fgets(linebuf, sizeof linebuf, proc_dag_f) != NULL; linenum++) {
591
592		/*
593		 * Skip the first two lines - they're headers.
594		 */
595		if (linenum <= 2)
596			continue;
597
598		p = &linebuf[0];
599
600		if (*p == '\0' || *p == '\n' || *p != 'D')
601			continue;  /* not a Dag line */
602
603		/*
604		 * Get the interface name.
605		 */
606		q = &name[0];
607		while (*p != '\0' && *p != ':') {
608			if (*p != ' ')
609				*q++ = tolower(*p++);
610			else
611				p++;
612		}
613		*q = '\0';
614
615		/*
616		 * Add an entry for this interface, with no addresses.
617		 */
618		p[strlen(p) - 1] = '\0'; /* get rid of \n */
619		if (pcap_add_if(devlistp, name, 0, strdup(p + 2), errbuf) == -1) {
620			/*
621			 * Failure.
622			 */
623			ret = -1;
624			break;
625		}
626	}
627	if (ret != -1) {
628		/*
629		 * Well, we didn't fail for any other reason; did we
630		 * fail due to an error reading the file?
631		 */
632		if (ferror(proc_dag_f)) {
633			(void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
634				  "Error reading /proc/dag: %s",
635				  pcap_strerror(errno));
636			ret = -1;
637		}
638	}
639
640	(void)fclose(proc_dag_f);
641	return (ret);
642}
643
644/*
645 * Installs the given bpf filter program in the given pcap structure.  There is
646 * no attempt to store the filter in kernel memory as that is not supported
647 * with DAG cards.
648 */
649static int
650dag_setfilter(pcap_t *p, struct bpf_program *fp)
651{
652	if (!p)
653		return -1;
654	if (!fp) {
655		strncpy(p->errbuf, "setfilter: No filter specified",
656			sizeof(p->errbuf));
657		return -1;
658	}
659
660	/* Make our private copy of the filter */
661
662	if (install_bpf_program(p, fp) < 0)
663		return -1;
664
665	p->md.use_bpf = 0;
666
667	return (0);
668}
669
670static int
671dag_set_datalink(pcap_t *p, int dlt)
672{
673	p->linktype = dlt;
674
675	return (0);
676}
677
678static int
679dag_setnonblock(pcap_t *p, int nonblock, char *errbuf)
680{
681	/*
682	 * Set non-blocking mode on the FD.
683	 * XXX - is that necessary?  If not, don't bother calling it,
684	 * and have a "dag_getnonblock()" function that looks at
685	 * "p->md.dag_offset_flags".
686	 */
687	if (pcap_setnonblock_fd(p, nonblock, errbuf) < 0)
688		return (-1);
689
690	if (nonblock) {
691		p->md.dag_offset_flags |= DAGF_NONBLOCK;
692	} else {
693		p->md.dag_offset_flags &= ~DAGF_NONBLOCK;
694	}
695	return (0);
696}
697
698static int
699dag_get_datalink(pcap_t *p)
700{
701	int daglinktype;
702
703	if (p->dlt_list == NULL && (p->dlt_list = malloc(2*sizeof(*(p->dlt_list)))) == NULL) {
704		(void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno));
705		return (-1);
706	}
707
708	/* Check the type through a dagapi call. */
709	daglinktype = dag_linktype(p->fd);
710
711	switch(daglinktype) {
712
713	case TYPE_HDLC_POS:
714		if (p->dlt_list != NULL) {
715			p->dlt_count = 2;
716			p->dlt_list[0] = DLT_CHDLC;
717			p->dlt_list[1] = DLT_PPP_SERIAL;
718		}
719		p->linktype = DLT_CHDLC;
720		break;
721
722	case TYPE_ETH:
723		/*
724		 * This is (presumably) a real Ethernet capture; give it a
725		 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
726		 * that an application can let you choose it, in case you're
727		 * capturing DOCSIS traffic that a Cisco Cable Modem
728		 * Termination System is putting out onto an Ethernet (it
729		 * doesn't put an Ethernet header onto the wire, it puts raw
730		 * DOCSIS frames out on the wire inside the low-level
731		 * Ethernet framing).
732		 */
733		if (p->dlt_list != NULL) {
734			p->dlt_count = 2;
735			p->dlt_list[0] = DLT_EN10MB;
736			p->dlt_list[1] = DLT_DOCSIS;
737		}
738		p->linktype = DLT_EN10MB;
739		break;
740
741	case TYPE_AAL5:
742	case TYPE_ATM:
743		if (p->dlt_list != NULL) {
744			p->dlt_count = 2;
745			p->dlt_list[0] = DLT_ATM_RFC1483;
746			p->dlt_list[1] = DLT_SUNATM;
747		}
748		p->linktype = DLT_ATM_RFC1483;
749		break;
750
751
752	case TYPE_LEGACY:
753		p->linktype = DLT_NULL;
754		break;
755
756	default:
757		snprintf(p->errbuf, sizeof(p->errbuf), "unknown DAG linktype %d\n", daglinktype);
758		return (-1);
759
760	}
761
762	return p->linktype;
763}
764