]>
The Tcpdump Group git mirrors - libpcap/blob - pcap-dag.c
2 * pcap-dag.c: Packet capture interface for Endace DAG card.
4 * The functionality of this code attempts to mimic that of pcap-linux as much
5 * as possible. This code is compiled in several different ways depending on
6 * whether DAG_ONLY and HAVE_DAG_API are defined. If HAVE_DAG_API is not
7 * defined it should not get compiled in, otherwise if DAG_ONLY is defined then
8 * the 'dag_' function calls are renamed to 'pcap_' equivalents. If DAG_ONLY
9 * is not defined then nothing is altered - the dag_ functions will be
10 * called as required from their pcap-linux/bpf equivalents.
12 * Author: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com)
15 * 2003 May - Jesper Peterson <support@endace.com>
16 * Code shuffled around to suit fad-xxx.c structure
17 * Added atexit() handler to stop DAG if application is too lazy
21 static const char rcsid
[] =
22 "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.1 2003-07-23 05:29:21 guy Exp $ (LBL)";
29 #include <sys/param.h> /* optionally get BSD define */
38 #include <sys/socket.h>
40 struct mbuf
; /* Squelch compiler warnings on some platforms for */
41 struct rtentry
; /* declarations in <net/if.h> */
47 #define MAX_DAG_SNAPLEN 2040
49 typedef struct pcap_dag_node
{
50 struct pcap_dag_node
*next
;
54 static pcap_dag_node_t
*pcap_dags
= NULL
;
55 static int atexit_handler_installed
= 0;
58 /* This code is reguired when compiling for a DAG device only. */
61 /* Replace dag function names with pcap equivalent. */
62 #define dag_stats pcap_stats
63 #define dag_read pcap_read
64 #define dag_open_live pcap_open_live
65 #define dag_platform_finddevs pcap_platform_finddevs
66 #define dag_setfilter pcap_setfilter
67 #define dag_set_datalink_platform pcap_set_datalink_platform
68 #define dag_platform_close pcap_platform_close
71 static void delete_pcap_dag(pcap_t
*p
) {
72 pcap_dag_node_t
*curr
= NULL
, *prev
= NULL
;
74 for (prev
= NULL
, curr
= pcap_dags
;
75 curr
!= NULL
&& curr
->p
!= p
;
76 prev
= curr
, curr
= curr
->next
) {
80 if (curr
!= NULL
&& curr
->p
== p
) {
82 prev
->next
= curr
->next
;
84 pcap_dags
= curr
->next
;
90 * Performs a graceful shutdown of the DAG card and frees dynamic memory held
91 * in the pcap_t structure.
94 void dag_platform_close(pcap_t
*p
) {
97 if (p
!= NULL
&& p
->md
.is_dag
&& p
->md
.device
!= NULL
) {
98 if(dag_stop(p
->fd
) < 0)
99 fprintf(stderr
,"dag_stop %s: %s\n", p
->md
.device
, strerror(errno
));
100 if(dag_close(p
->fd
) < 0)
101 fprintf(stderr
,"dag_close %s: %s\n", p
->md
.device
, strerror(errno
));
106 if (p
!= NULL
&& p
->md
.is_dag
) {
107 if(dag_stop(p
->fd
) < 0)
108 fprintf(stderr
,"dag_stop: %s\n", strerror(errno
));
109 if(dag_close(p
->fd
) < 0)
110 fprintf(stderr
,"dag_close: %s\n", strerror(errno
));
116 static void atexit_handler(void) {
117 while (pcap_dags
!= NULL
) {
118 dag_platform_close(pcap_dags
->p
);
122 static int new_pcap_dag(pcap_t
*p
) {
123 pcap_dag_node_t
*node
= NULL
;
125 if ((node
= malloc(sizeof(pcap_dag_node_t
))) == NULL
) {
129 if (!atexit_handler_installed
) {
130 atexit(atexit_handler
);
131 atexit_handler_installed
= 1;
134 node
->next
= pcap_dags
;
141 * Get pointer to the ERF header for the next packet in the input
142 * stream. This function blocks until a packet becomes available.
144 static dag_record_t
*get_next_dag_header(pcap_t
*p
) {
145 register dag_record_t
*record
;
148 if (p
->md
.dag_mem_top
- p
->md
.dag_mem_bottom
< dag_record_size
) {
149 p
->md
.dag_mem_top
= dag_offset(p
->fd
, &(p
->md
.dag_mem_bottom
), 0);
152 record
= (dag_record_t
*)(p
->md
.dag_mem_base
+ p
->md
.dag_mem_bottom
);
153 rlen
= ntohs(record
->rlen
);
154 while (p
->md
.dag_mem_top
- p
->md
.dag_mem_bottom
< rlen
) {
155 p
->md
.dag_mem_top
= dag_offset(p
->fd
, &(p
->md
.dag_mem_bottom
), 0);
156 record
= (dag_record_t
*)(p
->md
.dag_mem_base
+ p
->md
.dag_mem_bottom
);
157 rlen
= ntohs(record
->rlen
);
160 p
->md
.dag_mem_bottom
+= rlen
;
165 /* Size of payload in ATM packets */
166 #define ATM_CAPTURE_SIZE 48
168 /* Size of payload of Ethernet packet */
169 #define ETHERNET_LENGTH(h) min(ntohs((h)->wlen) - 4, ntohs((h)->rlen) - dag_record_size - 2 - (ntohs((h)->wlen) & 0x3))
171 /* Size of HDLC packet */
172 #define HDLC_LENGTH(h) min(ntohs((h)->wlen) - 4, ntohs((h)->rlen) - dag_record_size)
175 #define min(a, b) ((a) > (b) ? (b) : (a))
179 * Swap byte ordering of unsigned long long on a big endian
182 static unsigned long long swapll(unsigned long long ull
) {
183 #if (BYTE_ORDER == BIG_ENDIAN)
184 return ((ull
& 0xff00000000000000LL
) >> 56) |
185 ((ull
& 0x00ff000000000000LL
) >> 40) |
186 ((ull
& 0x0000ff0000000000LL
) >> 24) |
187 ((ull
& 0x000000ff00000000LL
) >> 8) |
188 ((ull
& 0x00000000ff000000LL
) << 8) |
189 ((ull
& 0x0000000000ff0000LL
) << 24) |
190 ((ull
& 0x000000000000ff00LL
) << 40) |
191 ((ull
& 0x00000000000000ffLL
) << 56) ;
198 * Read at most max_packets from the capture stream and call the callback
199 * for each of them. Returns the number of packets handled or -1 if an
200 * error occured. A blocking
202 int dag_read(pcap_t
*p
, int cnt
, pcap_handler callback
, u_char
*user
) {
204 int packet_len
= 0, caplen
= 0;
205 struct pcap_pkthdr pcap_header
;
207 dag_record_t
*header
;
208 register unsigned long long ts
;
210 /* Receive a single packet from the kernel */
211 header
= get_next_dag_header(p
);
212 dp
= ((u_char
*)header
) + dag_record_size
;
214 switch(header
->type
) {
216 packet_len
= ATM_CAPTURE_SIZE
;
217 caplen
= ATM_CAPTURE_SIZE
;
220 packet_len
= ntohs(header
->wlen
);
221 caplen
= ETHERNET_LENGTH(header
);
225 packet_len
= ntohs(header
->wlen
);
226 caplen
= HDLC_LENGTH(header
);
230 if (caplen
> p
->snapshot
)
231 caplen
= p
->snapshot
;
233 /* Run the packet filter if not using kernel filter */
234 if (p
->fcode
.bf_insns
) {
235 if (bpf_filter(p
->fcode
.bf_insns
, dp
, packet_len
, caplen
) == 0) {
236 /* rejected by filter */
241 /* convert between timestamp formats */
242 ts
= swapll(header
->ts
);
243 pcap_header
.ts
.tv_sec
= ts
>> 32;
244 ts
= ((ts
& 0xffffffffULL
) * 1000 * 1000);
245 ts
+= (ts
& 0x80000000ULL
) << 1; /* rounding */
246 pcap_header
.ts
.tv_usec
= ts
>> 32;
247 if (pcap_header
.ts
.tv_usec
>= 1000000) {
248 pcap_header
.ts
.tv_usec
-= 1000000;
249 pcap_header
.ts
.tv_sec
+= 1;
252 /* Fill in our own header data */
253 pcap_header
.caplen
= caplen
;
254 pcap_header
.len
= packet_len
;
259 p
->md
.stat
.ps_recv
++;
261 /* Call the user supplied callback function */
262 callback(user
, &pcap_header
, dp
);
268 * Get a handle for a live capture from the given DAG device. Passing a NULL
269 * device will result in a failure. The promisc flag is ignored because DAG
270 * cards are always promiscuous. The to_ms parameter is also ignored as it is
271 * not supported in hardware.
275 pcap_t
*dag_open_live(const char *device
, int snaplen
, int promisc
, int to_ms
, char *ebuf
) {
276 char conf
[30]; /* dag configure string */
279 if (device
== NULL
) {
280 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "device is NULL: %s", pcap_strerror(errno
));
283 /* Allocate a handle for this session. */
285 handle
= malloc(sizeof(*handle
));
286 if (handle
== NULL
) {
287 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "malloc %s: %s", device
, pcap_strerror(errno
));
291 /* Initialize some components of the pcap structure. */
293 memset(handle
, 0, sizeof(*handle
));
295 if (strstr(device
, "/dev") == NULL
) {
296 char * newDev
= (char *)malloc(strlen(device
) + 6);
298 strcat(newDev
, "/dev/");
299 strcat(newDev
,device
);
303 /* setup device parameters */
304 if((handle
->fd
= dag_open((char *)device
)) < 0) {
305 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "dag_open %s: %s", device
, pcap_strerror(errno
));
309 /* set the card snap length as specified by the specified snaplen parameter */
310 if (snaplen
> MAX_DAG_SNAPLEN
) {
311 snaplen
= MAX_DAG_SNAPLEN
;
313 snprintf(conf
, 30, "varlen slen=%d", (snaplen
% 4) ? (snaplen
+ 3) & ~3 : snaplen
); /* snap len has to be a multiple of 4 */
314 fprintf(stderr
, "Configuring DAG with '%s'.\n", conf
);
315 if(dag_configure(handle
->fd
, conf
) < 0) {
316 snprintf(ebuf
, PCAP_ERRBUF_SIZE
,"dag_configure %s: %s\n", device
, pcap_strerror(errno
));
320 if((handle
->md
.dag_mem_base
= dag_mmap(handle
->fd
)) == MAP_FAILED
) {
321 snprintf(ebuf
, PCAP_ERRBUF_SIZE
,"dag_mmap %s: %s\n", device
, pcap_strerror(errno
));
325 if(dag_start(handle
->fd
) < 0) {
326 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "dag_start %s: %s\n", device
, pcap_strerror(errno
));
331 * Important! You have to ensure bottom is properly
332 * initialized to zero on startup, it won't give you
333 * a compiler warning if you make this mistake!
335 handle
->md
.dag_mem_bottom
= 0;
336 handle
->md
.dag_mem_top
= 0;
337 handle
->md
.is_dag
= 1;
339 handle
->snapshot
= snaplen
;
340 /*handle->md.timeout = to_ms; */
344 handle
->md
.device
= strdup(device
);
347 if (handle
->md
.device
== NULL
) {
348 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "str_dup %s: %s\n", device
, pcap_strerror(errno
));
356 /* Check the type through a dagapi call.
358 switch(dag_linktype(handle
->fd
)) {
360 handle
->linktype
= DLT_CHDLC
;
361 fprintf(stderr
, "Set DAG linktype to %d (DLT_CHDLC)\n", handle
->linktype
);
364 handle
->linktype
= DLT_EN10MB
;
365 fprintf(stderr
, "Set DAG linktype to %d (DLT_EN10MB)\n", handle
->linktype
);
368 handle
->linktype
= DLT_ATM_RFC1483
;
369 fprintf(stderr
, "Set DAG linktype to %d (DLT_ATM_RFC1483)\n", handle
->linktype
);
372 handle
->linktype
= DLT_NULL
;
373 fprintf(stderr
, "Set DAG linktype to %d (DLT_NULL)\n", handle
->linktype
);
376 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "dag_open_live %s: unknown linktype %d\n", device
, dag_linktype(handle
->fd
));
380 handle
->bufsize
= 0;/*handle->snapshot;*/
382 if (new_pcap_dag(handle
) < 0) {
383 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "new_pcap_dag %s: %s\n", device
, pcap_strerror(errno
));
390 int dag_stats(pcap_t
*p
, struct pcap_stat
*ps
) {
391 /* This needs to be filled out correctly. Hopefully a dagapi call will
392 provide all necessary information.
394 /*p->md.stat.ps_recv = 0;*/
395 /*p->md.stat.ps_drop = 0;*/
403 * Get from "/proc/dag" all interfaces listed there; if they're
404 * already in the list of interfaces we have, that won't add another
405 * instance, but if they're not, that'll add them.
407 * We don't bother getting any addresses for them.
409 * We also don't fail if we couldn't open "/proc/dag"; we just leave
410 * the list of interfaces as is.
413 dag_platform_finddevs(pcap_if_t
**devlistp
, char *errbuf
)
419 char name
[512]; /* XXX - pick a size */
421 struct ifreq ifrflags
;
424 /* Quick exit if /proc/dag not readable */
425 proc_dag_f
= fopen("/proc/dag", "r");
426 if (proc_dag_f
== NULL
)
429 char dev
[16] = "dagx";
431 for (i
= '0'; ret
== 0 && i
<= '9'; i
++) {
433 if (pcap_add_if(devlistp
, dev
, 0, NULL
, errbuf
) == -1) {
445 fgets(linebuf
, sizeof linebuf
, proc_dag_f
) != NULL
; linenum
++) {
448 * Skip the first two lines - they're headers.
455 if (*p
== '\0' || *p
== '\n' || *p
!= 'D')
456 continue; /* not a Dag line */
459 * Get the interface name.
462 while (*p
!= '\0' && *p
!= ':') {
464 *q
++ = tolower(*p
++);
471 * Add an entry for this interface, with no addresses.
473 p
[strlen(p
) - 1] = '\0'; /* get rid of \n */
474 if (pcap_add_if(devlistp
, name
, 0, strdup(p
+ 2), errbuf
) == -1) {
484 * Well, we didn't fail for any other reason; did we
485 * fail due to an error reading the file?
487 if (ferror(proc_dag_f
)) {
488 (void)snprintf(errbuf
, PCAP_ERRBUF_SIZE
,
489 "Error reading /proc/dag: %s",
490 pcap_strerror(errno
));
495 (void)fclose(proc_dag_f
);
500 * Installs the gven bpf filter program in the given pcap structure. There is
501 * no attempt to store the filter in kernel memory as that is not supported
504 int dag_setfilter(pcap_t
*p
, struct bpf_program
*fp
) {
508 strncpy(p
->errbuf
, "setfilter: No filter specified",
513 /* Make our private copy of the filter */
515 if (install_bpf_program(p
, fp
) < 0) {
516 snprintf(p
->errbuf
, sizeof(p
->errbuf
),
517 "malloc: %s", pcap_strerror(errno
));
527 dag_set_datalink_platform(pcap_t
*p
, int dlt
)