]>
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.4 2003-07-25 04:42:02 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_read pcap_read
63 #define dag_open_live pcap_open_live
64 #define dag_platform_finddevs pcap_platform_finddevs
65 #define dag_set_datalink_platform pcap_set_datalink_platform
68 static int dag_setfilter(pcap_t
*p
, struct bpf_program
*fp
);
69 static int dag_stats(pcap_t
*p
, struct pcap_stat
*ps
);
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, frees dynamic memory held
91 * in the pcap_t structure, and closes the file descriptor for the DAG card.
94 static void dag_platform_close(pcap_t
*p
) {
97 if (p
!= NULL
&& 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
));
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
));
114 /* XXX - does "dag_close()" do this? If so, we don't need to. */
118 static void atexit_handler(void) {
119 while (pcap_dags
!= NULL
) {
120 dag_platform_close(pcap_dags
->p
);
124 static int new_pcap_dag(pcap_t
*p
) {
125 pcap_dag_node_t
*node
= NULL
;
127 if ((node
= malloc(sizeof(pcap_dag_node_t
))) == NULL
) {
131 if (!atexit_handler_installed
) {
132 atexit(atexit_handler
);
133 atexit_handler_installed
= 1;
136 node
->next
= pcap_dags
;
143 * Get pointer to the ERF header for the next packet in the input
144 * stream. This function blocks until a packet becomes available.
146 static dag_record_t
*get_next_dag_header(pcap_t
*p
) {
147 register dag_record_t
*record
;
150 if (p
->md
.dag_mem_top
- p
->md
.dag_mem_bottom
< dag_record_size
) {
151 p
->md
.dag_mem_top
= dag_offset(p
->fd
, &(p
->md
.dag_mem_bottom
), 0);
154 record
= (dag_record_t
*)(p
->md
.dag_mem_base
+ p
->md
.dag_mem_bottom
);
155 rlen
= ntohs(record
->rlen
);
156 while (p
->md
.dag_mem_top
- p
->md
.dag_mem_bottom
< rlen
) {
157 p
->md
.dag_mem_top
= dag_offset(p
->fd
, &(p
->md
.dag_mem_bottom
), 0);
158 record
= (dag_record_t
*)(p
->md
.dag_mem_base
+ p
->md
.dag_mem_bottom
);
159 rlen
= ntohs(record
->rlen
);
162 p
->md
.dag_mem_bottom
+= rlen
;
167 /* Size of payload in ATM packets */
168 #define ATM_CAPTURE_SIZE 48
170 /* Size of payload of Ethernet packet */
171 #define ETHERNET_LENGTH(h) min(ntohs((h)->wlen) - 4, ntohs((h)->rlen) - dag_record_size - 2 - (ntohs((h)->wlen) & 0x3))
173 /* Size of HDLC packet */
174 #define HDLC_LENGTH(h) min(ntohs((h)->wlen) - 4, ntohs((h)->rlen) - dag_record_size)
177 #define min(a, b) ((a) > (b) ? (b) : (a))
181 * Swap byte ordering of unsigned long long on a big endian
184 static unsigned long long swapll(unsigned long long ull
) {
185 #if (BYTE_ORDER == BIG_ENDIAN)
186 return ((ull
& 0xff00000000000000LL
) >> 56) |
187 ((ull
& 0x00ff000000000000LL
) >> 40) |
188 ((ull
& 0x0000ff0000000000LL
) >> 24) |
189 ((ull
& 0x000000ff00000000LL
) >> 8) |
190 ((ull
& 0x00000000ff000000LL
) << 8) |
191 ((ull
& 0x0000000000ff0000LL
) << 24) |
192 ((ull
& 0x000000000000ff00LL
) << 40) |
193 ((ull
& 0x00000000000000ffLL
) << 56) ;
200 * Read at most max_packets from the capture stream and call the callback
201 * for each of them. Returns the number of packets handled or -1 if an
202 * error occured. A blocking
204 int dag_read(pcap_t
*p
, int cnt
, pcap_handler callback
, u_char
*user
) {
206 int packet_len
= 0, caplen
= 0;
207 struct pcap_pkthdr pcap_header
;
209 dag_record_t
*header
;
210 register unsigned long long ts
;
212 /* Receive a single packet from the kernel */
213 header
= get_next_dag_header(p
);
214 dp
= ((u_char
*)header
) + dag_record_size
;
216 switch(header
->type
) {
218 packet_len
= ATM_CAPTURE_SIZE
;
219 caplen
= ATM_CAPTURE_SIZE
;
222 packet_len
= ntohs(header
->wlen
);
223 caplen
= ETHERNET_LENGTH(header
);
227 packet_len
= ntohs(header
->wlen
);
228 caplen
= HDLC_LENGTH(header
);
232 if (caplen
> p
->snapshot
)
233 caplen
= p
->snapshot
;
235 /* Run the packet filter if not using kernel filter */
236 if (p
->fcode
.bf_insns
) {
237 if (bpf_filter(p
->fcode
.bf_insns
, dp
, packet_len
, caplen
) == 0) {
238 /* rejected by filter */
243 /* convert between timestamp formats */
244 ts
= swapll(header
->ts
);
245 pcap_header
.ts
.tv_sec
= ts
>> 32;
246 ts
= ((ts
& 0xffffffffULL
) * 1000 * 1000);
247 ts
+= (ts
& 0x80000000ULL
) << 1; /* rounding */
248 pcap_header
.ts
.tv_usec
= ts
>> 32;
249 if (pcap_header
.ts
.tv_usec
>= 1000000) {
250 pcap_header
.ts
.tv_usec
-= 1000000;
251 pcap_header
.ts
.tv_sec
+= 1;
254 /* Fill in our own header data */
255 pcap_header
.caplen
= caplen
;
256 pcap_header
.len
= packet_len
;
261 p
->md
.stat
.ps_recv
++;
263 /* Call the user supplied callback function */
264 callback(user
, &pcap_header
, dp
);
270 * Get a handle for a live capture from the given DAG device. Passing a NULL
271 * device will result in a failure. The promisc flag is ignored because DAG
272 * cards are always promiscuous. The to_ms parameter is also ignored as it is
273 * not supported in hardware.
277 pcap_t
*dag_open_live(const char *device
, int snaplen
, int promisc
, int to_ms
, char *ebuf
) {
278 char conf
[30]; /* dag configure string */
281 if (device
== NULL
) {
282 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "device is NULL: %s", pcap_strerror(errno
));
285 /* Allocate a handle for this session. */
287 handle
= malloc(sizeof(*handle
));
288 if (handle
== NULL
) {
289 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "malloc %s: %s", device
, pcap_strerror(errno
));
293 /* Initialize some components of the pcap structure. */
295 memset(handle
, 0, sizeof(*handle
));
297 if (strstr(device
, "/dev") == NULL
) {
298 char * newDev
= (char *)malloc(strlen(device
) + 6);
300 strcat(newDev
, "/dev/");
301 strcat(newDev
,device
);
305 /* setup device parameters */
306 if((handle
->fd
= dag_open((char *)device
)) < 0) {
307 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "dag_open %s: %s", device
, pcap_strerror(errno
));
311 /* set the card snap length as specified by the specified snaplen parameter */
312 if (snaplen
> MAX_DAG_SNAPLEN
) {
313 snaplen
= MAX_DAG_SNAPLEN
;
315 snprintf(conf
, 30, "varlen slen=%d", (snaplen
% 4) ? (snaplen
+ 3) & ~3 : snaplen
); /* snap len has to be a multiple of 4 */
316 fprintf(stderr
, "Configuring DAG with '%s'.\n", conf
);
317 if(dag_configure(handle
->fd
, conf
) < 0) {
318 snprintf(ebuf
, PCAP_ERRBUF_SIZE
,"dag_configure %s: %s\n", device
, pcap_strerror(errno
));
322 if((handle
->md
.dag_mem_base
= dag_mmap(handle
->fd
)) == MAP_FAILED
) {
323 snprintf(ebuf
, PCAP_ERRBUF_SIZE
,"dag_mmap %s: %s\n", device
, pcap_strerror(errno
));
327 if(dag_start(handle
->fd
) < 0) {
328 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "dag_start %s: %s\n", device
, pcap_strerror(errno
));
333 * Important! You have to ensure bottom is properly
334 * initialized to zero on startup, it won't give you
335 * a compiler warning if you make this mistake!
337 handle
->md
.dag_mem_bottom
= 0;
338 handle
->md
.dag_mem_top
= 0;
339 handle
->md
.is_dag
= 1;
341 handle
->snapshot
= snaplen
;
342 /*handle->md.timeout = to_ms; */
346 handle
->md
.device
= strdup(device
);
349 if (handle
->md
.device
== NULL
) {
350 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "str_dup %s: %s\n", device
, pcap_strerror(errno
));
358 /* Check the type through a dagapi call.
360 switch(dag_linktype(handle
->fd
)) {
362 handle
->linktype
= DLT_CHDLC
;
363 fprintf(stderr
, "Set DAG linktype to %d (DLT_CHDLC)\n", handle
->linktype
);
366 handle
->linktype
= DLT_EN10MB
;
367 fprintf(stderr
, "Set DAG linktype to %d (DLT_EN10MB)\n", handle
->linktype
);
370 handle
->linktype
= DLT_ATM_RFC1483
;
371 fprintf(stderr
, "Set DAG linktype to %d (DLT_ATM_RFC1483)\n", handle
->linktype
);
374 handle
->linktype
= DLT_NULL
;
375 fprintf(stderr
, "Set DAG linktype to %d (DLT_NULL)\n", handle
->linktype
);
378 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "dag_open_live %s: unknown linktype %d\n", device
, dag_linktype(handle
->fd
));
382 handle
->bufsize
= 0;/*handle->snapshot;*/
384 if (new_pcap_dag(handle
) < 0) {
385 snprintf(ebuf
, PCAP_ERRBUF_SIZE
, "new_pcap_dag %s: %s\n", device
, pcap_strerror(errno
));
389 handle
->setfilter_op
= dag_setfilter
;
390 handle
->stats_op
= dag_stats
;
391 handle
->close_op
= dag_platform_close
;
396 static int dag_stats(pcap_t
*p
, struct pcap_stat
*ps
) {
397 /* This needs to be filled out correctly. Hopefully a dagapi call will
398 provide all necessary information.
400 /*p->md.stat.ps_recv = 0;*/
401 /*p->md.stat.ps_drop = 0;*/
409 * Get from "/proc/dag" all interfaces listed there; if they're
410 * already in the list of interfaces we have, that won't add another
411 * instance, but if they're not, that'll add them.
413 * We don't bother getting any addresses for them.
415 * We also don't fail if we couldn't open "/proc/dag"; we just leave
416 * the list of interfaces as is.
419 dag_platform_finddevs(pcap_if_t
**devlistp
, char *errbuf
)
425 char name
[512]; /* XXX - pick a size */
427 struct ifreq ifrflags
;
430 /* Quick exit if /proc/dag not readable */
431 proc_dag_f
= fopen("/proc/dag", "r");
432 if (proc_dag_f
== NULL
)
435 char dev
[16] = "dagx";
437 for (i
= '0'; ret
== 0 && i
<= '9'; i
++) {
439 if (pcap_add_if(devlistp
, dev
, 0, NULL
, errbuf
) == -1) {
451 fgets(linebuf
, sizeof linebuf
, proc_dag_f
) != NULL
; linenum
++) {
454 * Skip the first two lines - they're headers.
461 if (*p
== '\0' || *p
== '\n' || *p
!= 'D')
462 continue; /* not a Dag line */
465 * Get the interface name.
468 while (*p
!= '\0' && *p
!= ':') {
470 *q
++ = tolower(*p
++);
477 * Add an entry for this interface, with no addresses.
479 p
[strlen(p
) - 1] = '\0'; /* get rid of \n */
480 if (pcap_add_if(devlistp
, name
, 0, strdup(p
+ 2), errbuf
) == -1) {
490 * Well, we didn't fail for any other reason; did we
491 * fail due to an error reading the file?
493 if (ferror(proc_dag_f
)) {
494 (void)snprintf(errbuf
, PCAP_ERRBUF_SIZE
,
495 "Error reading /proc/dag: %s",
496 pcap_strerror(errno
));
501 (void)fclose(proc_dag_f
);
506 * Installs the gven bpf filter program in the given pcap structure. There is
507 * no attempt to store the filter in kernel memory as that is not supported
510 static int dag_setfilter(pcap_t
*p
, struct bpf_program
*fp
) {
514 strncpy(p
->errbuf
, "setfilter: No filter specified",
519 /* Make our private copy of the filter */
521 if (install_bpf_program(p
, fp
) < 0) {
522 snprintf(p
->errbuf
, sizeof(p
->errbuf
),
523 "malloc: %s", pcap_strerror(errno
));
533 dag_set_datalink_platform(pcap_t
*p
, int dlt
)