]> The Tcpdump Group git mirrors - libpcap/blob - pcap-dag.c
Add support for sending packets; includes contributions from Mark
[libpcap] / pcap-dag.c
1 /*
2 * pcap-dag.c: Packet capture interface for Endace DAG card.
3 *
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.
11 *
12 * Authors: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com)
13 * Modifications: Jesper Peterson, Koryn Grant <support@endace.com>
14 */
15
16 #ifndef lint
17 static const char rcsid[] _U_ =
18 "@(#) $Header: /tcpdump/master/libpcap/pcap-dag.c,v 1.18 2004-03-23 19:18:04 guy Exp $ (LBL)";
19 #endif
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <sys/param.h> /* optionally get BSD define */
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30
31 #include "pcap-int.h"
32
33 #include <ctype.h>
34 #include <netinet/in.h>
35 #include <sys/mman.h>
36 #include <sys/socket.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39
40 struct mbuf; /* Squelch compiler warnings on some platforms for */
41 struct rtentry; /* declarations in <net/if.h> */
42 #include <net/if.h>
43
44 #include <dagnew.h>
45 #include <dagapi.h>
46
47 #define MIN_DAG_SNAPLEN 12
48 #define MAX_DAG_SNAPLEN 2040
49 #define ATM_CELL_SIZE 52
50 #define ATM_HDR_SIZE 4
51
52 /* SunATM pseudo header */
53 struct sunatm_hdr {
54 unsigned char flags; /* destination and traffic type */
55 unsigned char vpi; /* VPI */
56 unsigned short vci; /* VCI */
57 };
58
59 typedef struct pcap_dag_node {
60 struct pcap_dag_node *next;
61 pcap_t *p;
62 pid_t pid;
63 } pcap_dag_node_t;
64
65 static pcap_dag_node_t *pcap_dags = NULL;
66 static int atexit_handler_installed = 0;
67 static const unsigned short endian_test_word = 0x0100;
68
69 #define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word))
70
71 /*
72 * Swap byte ordering of unsigned long long timestamp on a big endian
73 * machine.
74 */
75 #define SWAP_TS(ull) ((ull & 0xff00000000000000LL) >> 56) | \
76 ((ull & 0x00ff000000000000LL) >> 40) | \
77 ((ull & 0x0000ff0000000000LL) >> 24) | \
78 ((ull & 0x000000ff00000000LL) >> 8) | \
79 ((ull & 0x00000000ff000000LL) << 8) | \
80 ((ull & 0x0000000000ff0000LL) << 24) | \
81 ((ull & 0x000000000000ff00LL) << 40) | \
82 ((ull & 0x00000000000000ffLL) << 56)
83
84
85 #ifdef DAG_ONLY
86 /* This code is required when compiling for a DAG device only. */
87 #include "pcap-dag.h"
88
89 /* Replace dag function names with pcap equivalent. */
90 #define dag_open_live pcap_open_live
91 #define dag_platform_finddevs pcap_platform_finddevs
92 #endif /* DAG_ONLY */
93
94 static int dag_setfilter(pcap_t *p, struct bpf_program *fp);
95 static int dag_stats(pcap_t *p, struct pcap_stat *ps);
96 static int dag_set_datalink(pcap_t *p, int dlt);
97 static int dag_get_datalink(pcap_t *p);
98 static int dag_setnonblock(pcap_t *p, int nonblock, char *errbuf);
99
100 static void
101 delete_pcap_dag(pcap_t *p)
102 {
103 pcap_dag_node_t *curr = NULL, *prev = NULL;
104
105 for (prev = NULL, curr = pcap_dags; curr != NULL && curr->p != p; prev = curr, curr = curr->next) {
106 /* empty */
107 }
108
109 if (curr != NULL && curr->p == p) {
110 if (prev != NULL) {
111 prev->next = curr->next;
112 } else {
113 pcap_dags = curr->next;
114 }
115 }
116 }
117
118 /*
119 * Performs a graceful shutdown of the DAG card, frees dynamic memory held
120 * in the pcap_t structure, and closes the file descriptor for the DAG card.
121 */
122
123 static void
124 dag_platform_close(pcap_t *p)
125 {
126
127 #ifdef linux
128 if (p != NULL && p->md.device != NULL) {
129 if(dag_stop(p->fd) < 0)
130 fprintf(stderr,"dag_stop %s: %s\n", p->md.device, strerror(errno));
131 if(dag_close(p->fd) < 0)
132 fprintf(stderr,"dag_close %s: %s\n", p->md.device, strerror(errno));
133
134 free(p->md.device);
135 }
136 #else
137 if (p != NULL) {
138 if(dag_stop(p->fd) < 0)
139 fprintf(stderr,"dag_stop: %s\n", strerror(errno));
140 if(dag_close(p->fd) < 0)
141 fprintf(stderr,"dag_close: %s\n", strerror(errno));
142 }
143 #endif
144 delete_pcap_dag(p);
145 /* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */
146 }
147
148 static void
149 atexit_handler(void)
150 {
151 while (pcap_dags != NULL) {
152 if (pcap_dags->pid == getpid()) {
153 dag_platform_close(pcap_dags->p);
154 } else {
155 delete_pcap_dag(pcap_dags->p);
156 }
157 }
158 }
159
160 static int
161 new_pcap_dag(pcap_t *p)
162 {
163 pcap_dag_node_t *node = NULL;
164
165 if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) {
166 return -1;
167 }
168
169 if (!atexit_handler_installed) {
170 atexit(atexit_handler);
171 atexit_handler_installed = 1;
172 }
173
174 node->next = pcap_dags;
175 node->p = p;
176 node->pid = getpid();
177
178 pcap_dags = node;
179
180 return 0;
181 }
182
183 /*
184 * Read at most max_packets from the capture stream and call the callback
185 * for each of them. Returns the number of packets handled, -1 if an
186 * error occured, or -2 if we were told to break out of the loop.
187 */
188 static int
189 dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
190 {
191 unsigned int processed = 0;
192 int flags = p->md.dag_offset_flags;
193 unsigned int nonblocking = flags & DAGF_NONBLOCK;
194
195 for (;;)
196 {
197 /* Get the next bufferful of packets (if necessary). */
198 while (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size) {
199
200 /*
201 * Has "pcap_breakloop()" been called?
202 */
203 if (p->break_loop) {
204 /*
205 * Yes - clear the flag that indicates that
206 * it has, and return -2 to indicate that
207 * we were told to break out of the loop.
208 */
209 p->break_loop = 0;
210 return -2;
211 }
212
213 p->md.dag_mem_top = dag_offset(p->fd, &(p->md.dag_mem_bottom), flags);
214 if (nonblocking && (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size))
215 {
216 /* Pcap is configured to process only available packets, and there aren't any. */
217 return 0;
218 }
219 }
220
221 /* Process the packets. */
222 while (p->md.dag_mem_top - p->md.dag_mem_bottom >= dag_record_size) {
223
224 unsigned short packet_len = 0;
225 int caplen = 0;
226 struct pcap_pkthdr pcap_header;
227
228 dag_record_t *header = (dag_record_t *)(p->md.dag_mem_base + p->md.dag_mem_bottom);
229 u_char *dp = ((u_char *)header) + dag_record_size;
230 unsigned short rlen;
231
232 /*
233 * Has "pcap_breakloop()" been called?
234 */
235 if (p->break_loop) {
236 /*
237 * Yes - clear the flag that indicates that
238 * it has, and return -2 to indicate that
239 * we were told to break out of the loop.
240 */
241 p->break_loop = 0;
242 return -2;
243 }
244
245 if (IS_BIGENDIAN()) {
246 rlen = header->rlen;
247 } else {
248 rlen = ntohs(header->rlen);
249 }
250 p->md.dag_mem_bottom += rlen;
251
252 switch(header->type) {
253 case TYPE_AAL5:
254 case TYPE_ATM:
255 if (header->type == TYPE_AAL5) {
256 if (IS_BIGENDIAN()) {
257 packet_len = header->wlen;
258 } else {
259 packet_len = ntohs(header->wlen);
260 }
261 caplen = rlen - dag_record_size;
262 } else {
263 caplen = packet_len = ATM_CELL_SIZE;
264 }
265 if (p->linktype == DLT_SUNATM) {
266 struct sunatm_hdr *sunatm = (struct sunatm_hdr *)dp;
267 unsigned long rawatm;
268 if (IS_BIGENDIAN()) {
269 rawatm = *((unsigned long *)dp);
270 sunatm->vci = (rawatm >> 4) & 0xffff;
271 } else {
272 rawatm = ntohl(*((unsigned long *)dp));
273 sunatm->vci = htons((rawatm >> 4) & 0xffff);
274 }
275 sunatm->vpi = (rawatm >> 20) & 0x00ff;
276 sunatm->flags = ((header->flags.iface & 1) ? 0x80 : 0x00) |
277 ((sunatm->vpi == 0 && sunatm->vci == htons(5)) ? 6 :
278 ((sunatm->vpi == 0 && sunatm->vci == htons(16)) ? 5 :
279 ((dp[ATM_HDR_SIZE] == 0xaa &&
280 dp[ATM_HDR_SIZE+1] == 0xaa &&
281 dp[ATM_HDR_SIZE+2] == 0x03) ? 2 : 1)));
282
283 } else {
284 packet_len -= ATM_HDR_SIZE;
285 caplen -= ATM_HDR_SIZE;
286 dp += ATM_HDR_SIZE;
287 }
288 break;
289
290 case TYPE_ETH:
291 if (IS_BIGENDIAN()) {
292 packet_len = header->wlen;
293 } else {
294 packet_len = ntohs(header->wlen);
295 }
296 packet_len -= (p->md.dag_fcs_bits >> 3);
297 caplen = rlen - dag_record_size - 2;
298 if (caplen > packet_len) {
299 caplen = packet_len;
300 }
301 dp += 2;
302 break;
303
304 case TYPE_HDLC_POS:
305 if (IS_BIGENDIAN()) {
306 packet_len = header->wlen;
307 } else {
308 packet_len = ntohs(header->wlen);
309 }
310 packet_len -= (p->md.dag_fcs_bits >> 3);
311 caplen = rlen - dag_record_size;
312 if (caplen > packet_len) {
313 caplen = packet_len;
314 }
315 break;
316 }
317
318 if (caplen > p->snapshot)
319 caplen = p->snapshot;
320
321 /* Count lost packets. */
322 if (header->lctr) {
323 if (p->md.stat.ps_drop > (UINT_MAX - ntohs(header->lctr))) {
324 p->md.stat.ps_drop = UINT_MAX;
325 } else {
326 p->md.stat.ps_drop += ntohs(header->lctr);
327 }
328 }
329
330 /* Run the packet filter if there is one. */
331 if ((p->fcode.bf_insns == NULL) || bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
332
333 /* convert between timestamp formats */
334 register unsigned long long ts;
335
336 if (IS_BIGENDIAN()) {
337 ts = SWAP_TS(header->ts);
338 } else {
339 ts = header->ts;
340 }
341
342 pcap_header.ts.tv_sec = ts >> 32;
343 ts = (ts & 0xffffffffULL) * 1000000;
344 ts += 0x80000000; /* rounding */
345 pcap_header.ts.tv_usec = ts >> 32;
346 if (pcap_header.ts.tv_usec >= 1000000) {
347 pcap_header.ts.tv_usec -= 1000000;
348 pcap_header.ts.tv_sec++;
349 }
350
351 /* Fill in our own header data */
352 pcap_header.caplen = caplen;
353 pcap_header.len = packet_len;
354
355 /* Count the packet. */
356 p->md.stat.ps_recv++;
357
358 /* Call the user supplied callback function */
359 callback(user, &pcap_header, dp);
360
361 /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */
362 processed++;
363 if (processed == cnt)
364 {
365 /* Reached the user-specified limit. */
366 return cnt;
367 }
368 }
369 }
370
371 if (nonblocking || processed)
372 {
373 return processed;
374 }
375 }
376
377 return processed;
378 }
379
380 static int
381 dag_inject(pcap_t *p, const void *buf _U_, size_t size _U_)
382 {
383 strlcpy(p->errbuf, "Sending packets isn't supported on DAG cards",
384 PCAP_ERRBUF_SIZE);
385 return (-1);
386 }
387
388 /*
389 * Get a handle for a live capture from the given DAG device. Passing a NULL
390 * device will result in a failure. The promisc flag is ignored because DAG
391 * cards are always promiscuous. The to_ms parameter is also ignored as it is
392 * not supported in hardware.
393 *
394 * See also pcap(3).
395 */
396 pcap_t *
397 dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf)
398 {
399 char conf[30]; /* dag configure string */
400 pcap_t *handle;
401 char *s;
402 int n;
403
404 if (device == NULL) {
405 snprintf(ebuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno));
406 return NULL;
407 }
408 /* Allocate a handle for this session. */
409
410 handle = malloc(sizeof(*handle));
411 if (handle == NULL) {
412 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc %s: %s", device, pcap_strerror(errno));
413 return NULL;
414 }
415
416 /* Initialize some components of the pcap structure. */
417
418 memset(handle, 0, sizeof(*handle));
419
420 if (strstr(device, "/dev") == NULL) {
421 char * newDev = (char *)malloc(strlen(device) + 6);
422 newDev[0] = '\0';
423 strcat(newDev, "/dev/");
424 strcat(newDev,device);
425 device = newDev;
426 } else {
427 device = strdup(device);
428 }
429
430 if (device == NULL) {
431 snprintf(ebuf, PCAP_ERRBUF_SIZE, "str_dup: %s\n", pcap_strerror(errno));
432 goto fail;
433 }
434
435 /* setup device parameters */
436 if((handle->fd = dag_open((char *)device)) < 0) {
437 snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno));
438 goto fail;
439 }
440
441 /* set the card snap length to the specified snaplen parameter */
442 if (snaplen == 0 || snaplen > MAX_DAG_SNAPLEN) {
443 snaplen = MAX_DAG_SNAPLEN;
444 } else if (snaplen < MIN_DAG_SNAPLEN) {
445 snaplen = MIN_DAG_SNAPLEN;
446 }
447 /* snap len has to be a multiple of 4 */
448 snprintf(conf, 30, "varlen slen=%d", (snaplen + 3) & ~3);
449
450 if(dag_configure(handle->fd, conf) < 0) {
451 snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno));
452 goto fail;
453 }
454
455 if((handle->md.dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) {
456 snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno));
457 goto fail;
458 }
459
460 if(dag_start(handle->fd) < 0) {
461 snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno));
462 goto fail;
463 }
464
465 /*
466 * Important! You have to ensure bottom is properly
467 * initialized to zero on startup, it won't give you
468 * a compiler warning if you make this mistake!
469 */
470 handle->md.dag_mem_bottom = 0;
471 handle->md.dag_mem_top = 0;
472
473 /* TODO: query the card */
474 handle->md.dag_fcs_bits = 32;
475 if ((s = getenv("ERF_FCS_BITS")) != NULL) {
476 if ((n = atoi(s)) == 0 || n == 16|| n == 32) {
477 handle->md.dag_fcs_bits = n;
478 } else {
479 snprintf(ebuf, PCAP_ERRBUF_SIZE,
480 "pcap_open_live %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n);
481 goto fail;
482 }
483 }
484
485 handle->snapshot = snaplen;
486 /*handle->md.timeout = to_ms; */
487
488 handle->linktype = -1;
489 if (dag_get_datalink(handle) < 0) {
490 strcpy(ebuf, handle->errbuf);
491 goto fail;
492 }
493
494 handle->bufsize = 0;
495
496 if (new_pcap_dag(handle) < 0) {
497 snprintf(ebuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno));
498 goto fail;
499 }
500
501 /*
502 * "select()" and "poll()" don't (yet) work on DAG device descriptors.
503 */
504 handle->selectable_fd = -1;
505
506 #ifdef linux
507 handle->md.device = (char *)device;
508 #else
509 free((char *)device);
510 device = NULL;
511 #endif
512
513 handle->read_op = dag_read;
514 handle->inject_op = dag_inject;
515 handle->setfilter_op = dag_setfilter;
516 handle->set_datalink_op = dag_set_datalink;
517 handle->getnonblock_op = pcap_getnonblock_fd;
518 handle->setnonblock_op = dag_setnonblock;
519 handle->stats_op = dag_stats;
520 handle->close_op = dag_platform_close;
521
522 return handle;
523
524 fail:
525 if (device != NULL) {
526 free((char *)device);
527 }
528 if (handle != NULL) {
529 /*
530 * Get rid of any link-layer type list we allocated.
531 */
532 if (handle->dlt_list != NULL) {
533 free(handle->dlt_list);
534 }
535 free(handle);
536 }
537
538 return NULL;
539 }
540
541 static int
542 dag_stats(pcap_t *p, struct pcap_stat *ps) {
543 /* This needs to be filled out correctly. Hopefully a dagapi call will
544 provide all necessary information.
545 */
546 /*p->md.stat.ps_recv = 0;*/
547 /*p->md.stat.ps_drop = 0;*/
548
549 *ps = p->md.stat;
550
551 return 0;
552 }
553
554 /*
555 * Get from "/proc/dag" all interfaces listed there; if they're
556 * already in the list of interfaces we have, that won't add another
557 * instance, but if they're not, that'll add them.
558 *
559 * We don't bother getting any addresses for them.
560 *
561 * We also don't fail if we couldn't open "/proc/dag"; we just leave
562 * the list of interfaces as is.
563 */
564 int
565 dag_platform_finddevs(pcap_if_t **devlistp, char *errbuf)
566 {
567 FILE *proc_dag_f;
568 char linebuf[512];
569 int linenum;
570 unsigned char *p;
571 char name[512]; /* XXX - pick a size */
572 char *q;
573 int ret = 0;
574
575 /* Quick exit if /proc/dag not readable */
576 proc_dag_f = fopen("/proc/dag", "r");
577 if (proc_dag_f == NULL)
578 {
579 int i;
580 char dev[16] = "dagx";
581
582 for (i = '0'; ret == 0 && i <= '9'; i++) {
583 dev[3] = i;
584 if (pcap_add_if(devlistp, dev, 0, NULL, errbuf) == -1) {
585 /*
586 * Failure.
587 */
588 ret = -1;
589 }
590 }
591
592 return (ret);
593 }
594
595 for (linenum = 1; fgets(linebuf, sizeof linebuf, proc_dag_f) != NULL; linenum++) {
596
597 /*
598 * Skip the first two lines - they're headers.
599 */
600 if (linenum <= 2)
601 continue;
602
603 p = &linebuf[0];
604
605 if (*p == '\0' || *p == '\n' || *p != 'D')
606 continue; /* not a Dag line */
607
608 /*
609 * Get the interface name.
610 */
611 q = &name[0];
612 while (*p != '\0' && *p != ':') {
613 if (*p != ' ')
614 *q++ = tolower(*p++);
615 else
616 p++;
617 }
618 *q = '\0';
619
620 /*
621 * Add an entry for this interface, with no addresses.
622 */
623 p[strlen(p) - 1] = '\0'; /* get rid of \n */
624 if (pcap_add_if(devlistp, name, 0, strdup(p + 2), errbuf) == -1) {
625 /*
626 * Failure.
627 */
628 ret = -1;
629 break;
630 }
631 }
632 if (ret != -1) {
633 /*
634 * Well, we didn't fail for any other reason; did we
635 * fail due to an error reading the file?
636 */
637 if (ferror(proc_dag_f)) {
638 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
639 "Error reading /proc/dag: %s",
640 pcap_strerror(errno));
641 ret = -1;
642 }
643 }
644
645 (void)fclose(proc_dag_f);
646 return (ret);
647 }
648
649 /*
650 * Installs the given bpf filter program in the given pcap structure. There is
651 * no attempt to store the filter in kernel memory as that is not supported
652 * with DAG cards.
653 */
654 static int
655 dag_setfilter(pcap_t *p, struct bpf_program *fp)
656 {
657 if (!p)
658 return -1;
659 if (!fp) {
660 strncpy(p->errbuf, "setfilter: No filter specified",
661 sizeof(p->errbuf));
662 return -1;
663 }
664
665 /* Make our private copy of the filter */
666
667 if (install_bpf_program(p, fp) < 0) {
668 snprintf(p->errbuf, sizeof(p->errbuf),
669 "malloc: %s", pcap_strerror(errno));
670 return -1;
671 }
672
673 p->md.use_bpf = 0;
674
675 return (0);
676 }
677
678 static int
679 dag_set_datalink(pcap_t *p, int dlt)
680 {
681 p->linktype = dlt;
682
683 return (0);
684 }
685
686 static int
687 dag_setnonblock(pcap_t *p, int nonblock, char *errbuf)
688 {
689 /*
690 * Set non-blocking mode on the FD.
691 * XXX - is that necessary? If not, don't bother calling it,
692 * and have a "dag_getnonblock()" function that looks at
693 * "p->md.dag_offset_flags".
694 */
695 if (pcap_setnonblock_fd(p, nonblock, errbuf) < 0)
696 return (-1);
697
698 if (nonblock) {
699 p->md.dag_offset_flags |= DAGF_NONBLOCK;
700 } else {
701 p->md.dag_offset_flags &= ~DAGF_NONBLOCK;
702 }
703 return (0);
704 }
705
706 static int
707 dag_get_datalink(pcap_t *p)
708 {
709 int daglinktype;
710
711 if (p->dlt_list == NULL && (p->dlt_list = malloc(2*sizeof(*(p->dlt_list)))) == NULL) {
712 (void)snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno));
713 return (-1);
714 }
715
716 /* Check the type through a dagapi call. */
717 daglinktype = dag_linktype(p->fd);
718
719 switch(daglinktype) {
720
721 case TYPE_HDLC_POS:
722 if (p->dlt_list != NULL) {
723 p->dlt_count = 2;
724 p->dlt_list[0] = DLT_CHDLC;
725 p->dlt_list[1] = DLT_PPP_SERIAL;
726 }
727 p->linktype = DLT_CHDLC;
728 break;
729
730 case TYPE_ETH:
731 /*
732 * This is (presumably) a real Ethernet capture; give it a
733 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
734 * that an application can let you choose it, in case you're
735 * capturing DOCSIS traffic that a Cisco Cable Modem
736 * Termination System is putting out onto an Ethernet (it
737 * doesn't put an Ethernet header onto the wire, it puts raw
738 * DOCSIS frames out on the wire inside the low-level
739 * Ethernet framing).
740 */
741 if (p->dlt_list != NULL) {
742 p->dlt_count = 2;
743 p->dlt_list[0] = DLT_EN10MB;
744 p->dlt_list[1] = DLT_DOCSIS;
745 }
746 p->linktype = DLT_EN10MB;
747 break;
748
749 case TYPE_AAL5:
750 case TYPE_ATM:
751 if (p->dlt_list != NULL) {
752 p->dlt_count = 2;
753 p->dlt_list[0] = DLT_ATM_RFC1483;
754 p->dlt_list[1] = DLT_SUNATM;
755 }
756 p->linktype = DLT_ATM_RFC1483;
757 break;
758
759
760 case TYPE_LEGACY:
761 p->linktype = DLT_NULL;
762 break;
763
764 default:
765 snprintf(p->errbuf, sizeof(p->errbuf), "unknown DAG linktype %d\n", daglinktype);
766 return (-1);
767
768 }
769
770 return p->linktype;
771 }