tcpdump mailing list archives

Patch for Endace DAG card support in libpcap


From: Jesper Peterson <jesper () endace com>
Date: Thu, 29 May 2003 10:06:54 +1200


Attached is a patch against the libpcap CVS tree to support packet
capture from Endace (http://www.endace.com) DAG cards for Linux and
FreeBSD platforms.

I would be grateful if it could be considered for inclusion in the
project proper.

The DAG support has been implemented as a new packet capture type
with a pcap-dag.c along the lines of the existing capture types.
Libpcap will be built with the DAG capture type if configured with
'--with-pcap=dag --with-dag=DIR'; the latter option being to give
configure a hint where to find the DAG support files for inclusion
in the library. Built this way the DAG capture type excludes any
native packet captures (linux or bpf).

If libpcap is configured with just '--with-dag=DIR' allowing the
capture type to default (or by specifying linux or bpf) the DAG
capture type will co-exist with the native capture type. This is
achieved by redirecting calls to pcap_xxx functions in pcap-linux.c
and pcap-bpf.c to dag_xxx functions in pcap-dag.c only if the stream
in question is actually a DAG stream. This is done by sections of
code like this in each pcap_xxx function:

    #ifdef HAVE_DAG_API
        if (handle->md.is_dag) {
                return dag_read(handle, max_packets, callback, user);
        }
    #endif /* HAVE_DAG_API */

An alternative to this would be to implement a more generic runtime
dispatcher possibly through function pointers in struct pcap_md. We
(Endace) would be willing to implement such a dispatcher if preferred.

-------------------
CHANGE NOTES:

Makefile.in:
    Add extra defines and objects to command lines depending on
    configuration results.

README.dag:
    New file documenting how to build libpcap with DAG support.

configure.in:
    Locate DAG API using '--with-dag=DIR' and if successful mangle
    Makefile.in accordingly. Modifications to 'configure' and
    'config.h.in' resulting from this change are not included in the
    patch.

inet.c:
    In pcap_lookupnet() treat DAG devices the same as the "any" (ie.
    ignore). Change only effected if HAVE_DAG_API is defined.

pcap-bpf.c:
    Redirect calls to pcap_xxx functions to dag_xxx if the device is
    really a DAG. Changes only effected if HAVE_DAG_API is defined.

pcap-dag.c:
    New file with main support for packet capture from DAG cards.

pcap-dag.h:
    New file with prototypes for DAG support only included if
    HAVE_DAG_API is defined and DAG_ONLY is not defined.

pcap-int.h:
    Added DAG device specific fields to pcap_md. Only effected if
    HAVE_DAG_API is defined

pcap-linux.c:
    Redirect calls to pcap_xxx functions to dag_xxx if the device is
    really a DAG. Changes only effected if HAVE_DAG_API is defined.

pcap.c:
    Added call to dag_platform_close(). Only effected if HAVE_DAG_API
    is defined.
-------------------

I appreciate any consideration you can give to accepting this patch.

Thank you,



--
Jesper Peterson, Senior Software Developer
http://www.endace.com, +64 7 839 0540

Common subdirectories: libpcap-current/CVS and libpcap/CVS
diff -c --unidirectional-new-file libpcap-current/Makefile.in libpcap/Makefile.in
*** libpcap-current/Makefile.in Thu May 22 15:25:21 2003
--- libpcap/Makefile.in Wed May  7 12:14:06 2003
***************
*** 44,50 ****
  CC = @CC@
  CCOPT = @V_CCOPT@
  INCLS = -I. @V_INCLS@
! DEFS = @DEFS@
  
  # Standard CFLAGS
  CFLAGS = $(CCOPT) $(INCLS) $(DEFS)
--- 44,51 ----
  CC = @CC@
  CCOPT = @V_CCOPT@
  INCLS = -I. @V_INCLS@
! DEFS = @DEFS@ @V_DEFS@
! LIBS = @V_LIBS@
  
  # Standard CFLAGS
  CFLAGS = $(CCOPT) $(INCLS) $(DEFS)
***************
*** 71,86 ****
  
  PSRC =        pcap-@V_PCAP@.c
  FSRC =  fad-@V_FINDALLDEVS@.c
  CSRC =        pcap.c inet.c gencode.c optimize.c nametoaddr.c \
        etherent.c savefile.c bpf_filter.c bpf_image.c bpf_dump.c
  GENSRC = scanner.c grammar.c version.c
  LIBOBJS = @LIBOBJS@
  
! SRC = $(PSRC) $(FSRC) $(CSRC) $(GENSRC)
  
  # We would like to say "OBJ = $(SRC:.c=.o)" but Ultrix's make cannot
  # hack the extra indirection
! OBJ = $(PSRC:.c=.o) $(FSRC:.c=.o) $(CSRC:.c=.o) $(GENSRC:.c=.o) # $(LIBOBJS)
  HDR = pcap.h pcap-int.h pcap-namedb.h pcap-nit.h pcap-pf.h \
        ethertype.h gencode.h gnuc.h
  GENHDR = \
--- 72,88 ----
  
  PSRC =        pcap-@V_PCAP@.c
  FSRC =  fad-@V_FINDALLDEVS@.c
+ SSRC =  @SSRC@
  CSRC =        pcap.c inet.c gencode.c optimize.c nametoaddr.c \
        etherent.c savefile.c bpf_filter.c bpf_image.c bpf_dump.c
  GENSRC = scanner.c grammar.c version.c
  LIBOBJS = @LIBOBJS@
  
! SRC = $(PSRC) $(FSRC) $(CSRC) $(SSRC) $(GENSRC)
  
  # We would like to say "OBJ = $(SRC:.c=.o)" but Ultrix's make cannot
  # hack the extra indirection
! OBJ = $(PSRC:.c=.o) $(FSRC:.c=.o) $(CSRC:.c=.o) $(SSRC:.c=.o) $(GENSRC:.c=.o) # $(LIBOBJS)
  HDR = pcap.h pcap-int.h pcap-namedb.h pcap-nit.h pcap-pf.h \
        ethertype.h gencode.h gnuc.h
  GENHDR = \
***************
*** 98,104 ****
  
  libpcap.a: $(OBJ)
        @rm -f $@
!       ar rc $@ $(OBJ)
        $(RANLIB) $@
  
  scanner.c: $(srcdir)/scanner.l
--- 100,106 ----
  
  libpcap.a: $(OBJ)
        @rm -f $@
!       ar rc $@ $(OBJ) $(LIBS)
        $(RANLIB) $@
  
  scanner.c: $(srcdir)/scanner.l
diff -c --unidirectional-new-file libpcap-current/README.dag libpcap/README.dag
*** libpcap-current/README.dag  Thu Jan  1 12:00:00 1970
--- libpcap/README.dag  Thu May 22 14:32:13 2003
***************
*** 0 ****
--- 1,48 ----
+ 
+ The following instructions apply if you have a Linux or FreeBSD platform and
+ want libpcap to support the DAG range of passive network monitoring cards from
+ Endace (http://www.endace.com, see below for further contact details).
+ 
+ 1) Install and build the DAG software distribution by following the
+ instructions supplied with that package. Current Endace customers can download
+ the DAG software distibution from https://www.endace.com
+ 
+ 2) Configure libcap. To allow the 'configure' script to locate the DAG
+ software distribution use the '--with-dag' option:
+ 
+         ./configure --with-dag=DIR
+ 
+ Where DIR is the root of the DAG software distribution, for example
+ /var/src/dag. If the DAG software is correctly detected 'configure' will
+ report:
+ 
+         checking whether we have DAG API... yes
+ 
+ If 'configure' reports that there is no DAG API, the directory may have been
+ incorrectly specified or the DAG software was not built before configuring
+ libpcap.
+ 
+ See also the libpcap INSTALL.txt file for further libpcap configuration
+ options.
+ 
+ Building libpcap at this stage will include support for both the native packet
+ capture stream (linux or bpf) and for capturing from DAG cards. To build
+ libpcap with only DAG support specify the capture type as 'dag' when
+ configuring libpcap:
+ 
+         ./configure --with-dag=DIR --with-pcap=dag
+ 
+ Applications built with libpcap configured in this way will only detect DAG
+ cards and will not capture from the native OS packet stream.
+ 
+ ----------------------------------------------------------------------
+ 
+ Please submit bug reports via <support () endace com>.
+ 
+ Please also visit our Web pages at:
+ 
+         http://www.endace.com/
+         http://dag.cs.waikato.ac.nz/
+ 
+ For more information about Endace DAG cards contact <sales () endace com>.
+ 
Common subdirectories: libpcap-current/SUNOS4 and libpcap/SUNOS4
Common subdirectories: libpcap-current/Win32 and libpcap/Win32
Common subdirectories: libpcap-current/bpf and libpcap/bpf
diff -c --unidirectional-new-file libpcap-current/configure.in libpcap/configure.in
*** libpcap-current/configure.in        Thu May 22 15:25:25 2003
--- libpcap/configure.in        Thu May 22 14:54:50 2003
***************
*** 11,17 ****
  
  AC_CANONICAL_SYSTEM
  
! AC_LBL_C_INIT(V_CCOPT, V_INCLS)
  AC_LBL_C_INLINE
  AC_C___ATTRIBUTE__
  
--- 11,17 ----
  
  AC_CANONICAL_SYSTEM
  
! AC_LBL_C_INIT(V_CCOPT, V_INCLS, V_LIBS)
  AC_LBL_C_INLINE
  AC_C___ATTRIBUTE__
  
***************
*** 217,222 ****
--- 217,226 ----
        AC_LBL_TPACKET_STATS
        ;;
  
+ dag)
+       V_DEFS="$V_DEFS -DDAG_ONLY"
+       ;;      
+ 
  null)
        AC_MSG_WARN(cannot determine packet capture interface)
        AC_MSG_WARN((see the INSTALL doc for more info))
***************
*** 235,240 ****
--- 239,297 ----
  fi
  AC_MSG_RESULT($ac_cv_lbl_proc_net_dev)
  
+ AC_ARG_WITH(dag, [  --with-dag=DIR          include DAG support from DIR])
+ ac_cv_lbl_dag_api=no
+ if test "$with_dag" != no; then
+ 
+       case "$V_PCAP" in
+       linux|bpf|dag)
+               ;;
+         *)
+               AC_MSG_ERROR(DAG support only available with 'linux' 'bpf' and 'dag' packet capture types)
+               ;;
+       esac
+ 
+       AC_MSG_CHECKING(whether we have DAG API)
+ 
+       if test -z "$with_dag" -o "$with_dag" = yes; then
+               dag_root=$srcdir/../dag
+       else
+               dag_root=$with_dag
+       fi
+ 
+       if test -r "$dag_root/tools" -a -r "$dag_root/include"; then
+               dag_tools_dir="$dag_root/tools"
+               dag_include_dir="$dag_root/include"
+       else
+               dag_tools_dir="$dag_root"
+               dag_include_dir="$dag_root"
+       fi
+ 
+       if test -r "$dag_include_dir/dagapi.h" -a -r "$dag_tools_dir/dagapi.o"; then
+               V_INCLS="$V_INCLS -I $dag_include_dir"
+               V_LIBS="$V_LIBS $dag_tools_dir/dagapi.o $dag_tools_dir/dagopts.o"
+               if test "$V_PCAP" != dag ; then
+                  SSRC="pcap-dag.c"
+               fi
+               ac_cv_lbl_dag_api=yes
+       else
+               ac_cv_lbl_dag_api=no
+       fi
+       AC_MSG_RESULT($ac_cv_lbl_dag_api)
+       if test $ac_cv_lbl_dag_api = no; then
+               if test ! -z "$with_dag"; then
+                       AC_MSG_ERROR(DAG API not found under directory $dag_root; use --without-dag)
+               fi
+       else
+               AC_DEFINE(HAVE_DAG_API, 1, [define if you have a DAG API])
+       fi
+ fi
+ 
+ if test "$V_PCAP" = dag -a "$ac_cv_lbl_dag_api" = no; then
+       AC_MSG_ERROR(Specifying the capture type as 'dag' requires the DAG API to be present; use --with-dag=DIR)
+ fi
+ 
+ 
  AC_LBL_LEX_AND_YACC(V_LEX, V_YACC, pcap_)
  if test "$V_LEX" = lex ; then
  # Some versions of lex can't handle the definitions section of scanner.l .
***************
*** 310,321 ****
--- 367,381 ----
  ln -s ${srcdir}/bpf/net net
  
  AC_SUBST(V_CCOPT)
+ AC_SUBST(V_DEFS)
  AC_SUBST(V_INCLS)
+ AC_SUBST(V_LIBS)
  AC_SUBST(V_LEX)
  AC_SUBST(V_PCAP)
  AC_SUBST(V_FINDALLDEVS)
  AC_SUBST(V_RANLIB)
  AC_SUBST(V_YACC)
+ AC_SUBST(SSRC)
  
  AC_PROG_INSTALL
  
diff -c --unidirectional-new-file libpcap-current/inet.c libpcap/inet.c
*** libpcap-current/inet.c      Thu May 22 15:25:30 2003
--- libpcap/inet.c      Mon May 12 10:31:38 2003
***************
*** 529,535 ****
         * has the network address and -mask "0.0.0.0" therefore catching
         * all traffic. Using NULL for the interface is the same as "any".
         */
!       if (!device || strcmp(device, "any") == 0) {
                *netp = *maskp = 0;
                return 0;
        }
--- 529,539 ----
         * has the network address and -mask "0.0.0.0" therefore catching
         * all traffic. Using NULL for the interface is the same as "any".
         */
!       if (!device || strcmp(device, "any") == 0
! #ifdef HAVE_DAG_API
!           || strstr(device, "dag") != NULL
! #endif
!           ) {
                *netp = *maskp = 0;
                return 0;
        }
Common subdirectories: libpcap-current/lbl and libpcap/lbl
Only in libpcap-current: libpcap
Common subdirectories: libpcap-current/linux-include and libpcap/linux-include
Common subdirectories: libpcap-current/packaging and libpcap/packaging
diff -c --unidirectional-new-file libpcap-current/pcap-bpf.c libpcap/pcap-bpf.c
*** libpcap-current/pcap-bpf.c  Thu May 22 15:25:32 2003
--- libpcap/pcap-bpf.c  Thu May 22 10:08:33 2003
***************
*** 93,98 ****
--- 93,102 ----
  
  #include "pcap-int.h"
  
+ #ifdef HAVE_DAG_API
+ #include "pcap-dag.h"
+ #endif /* HAVE_DAG_API */
+ 
  #ifdef HAVE_OS_PROTO_H
  #include "os-proto.h"
  #endif
***************
*** 104,109 ****
--- 108,119 ----
  {
        struct bpf_stat s;
  
+ #ifdef HAVE_DAG_API
+       if (p->md.is_dag) {
+               return dag_stats(p, ps);
+       }
+ #endif /* HAVE_DAG_API */
+ 
        /*
         * "ps_recv" counts packets handed to the filter, not packets
         * that passed the filter.  This includes packets later dropped
***************
*** 135,140 ****
--- 145,156 ----
        int n = 0;
        register u_char *bp, *ep;
  
+ #ifdef HAVE_DAG_API
+       if (p->md.is_dag) {
+               return dag_read(p, cnt, callback, user);
+       }
+ #endif /* HAVE_DAG_API */
+ 
   again:
        cc = p->cc;
        if (p->cc == 0) {
***************
*** 447,452 ****
--- 463,474 ----
        u_int v;
        pcap_t *p;
  
+ #ifdef HAVE_DAG_API
+       if (strstr(device, "dag")) {
+               return dag_open_live(device, snaplen, promisc, to_ms, ebuf);
+       }
+ #endif /* HAVE_DAG_API */
+ 
  #ifdef BIOCGDLTLIST
        bzero(&bdl, sizeof(bdl));
  #endif
***************
*** 719,730 ****
--- 741,763 ----
  int
  pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
  {
+ #ifdef HAVE_DAG_API
+       if (dag_platform_finddevs(alldevsp, errbuf) < 0)
+               return (-1);
+ #endif /* HAVE_DAG_API */
+ 
        return (0);
  }
  
  int
  pcap_setfilter(pcap_t *p, struct bpf_program *fp)
  {
+ #ifdef HAVE_DAG_API
+       if (p->md.is_dag) {
+               return dag_setfilter(p, fp);
+       }
+ #endif /* HAVE_DAG_API */
+ 
        /*
         * It looks that BPF code generated by gen_protochain() is not
         * compatible with some of kernel BPF code (for example BSD/OS 3.1).
***************
*** 747,752 ****
--- 780,791 ----
  int
  pcap_set_datalink_platform(pcap_t *p, int dlt)
  {
+ #ifdef HAVE_DAG_API
+       if (p->md.is_dag) {
+               return dag_set_datalink_platform(p, dlt);
+       }
+ #endif /* HAVE_DAG_API */
+ 
  #ifdef BIOCSDLT
        if (ioctl(p->fd, BIOCSDLT, &dlt) == -1) {
                (void) snprintf(p->errbuf, sizeof(p->errbuf),
diff -c --unidirectional-new-file libpcap-current/pcap-dag.c libpcap/pcap-dag.c
*** libpcap-current/pcap-dag.c  Thu Jan  1 12:00:00 1970
--- libpcap/pcap-dag.c  Thu May 22 10:08:05 2003
***************
*** 0 ****
--- 1,525 ----
+ /*
+  * pcap-dag.c: Packet capture interface for Endace DAG card.
+  *
+  * The functionality of this code attempts to mimic that of pcap-linux as much
+  * as possible.  This code is compiled in several different ways depending on
+  * whether DAG_ONLY and HAVE_DAG_API are defined.  If HAVE_DAG_API is not
+  * defined it should not get compiled in, otherwise if DAG_ONLY is defined then
+  * the 'dag_' function calls are renamed to 'pcap_' equivalents.  If DAG_ONLY
+  * is not defined then nothing is altered - the dag_ functions will be
+  * called as required from their pcap-linux/bpf equivalents.
+  *
+  * Author: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com)
+  *
+  * Modifications:
+  *   2003 May - Jesper Peterson <support () endace com>
+  *              Code shuffled around to suit fad-xxx.c structure
+  *              Added atexit() handler to stop DAG if application is too lazy
+  */
+ 
+ #ifndef lint
+ static const char rcsid[] =
+     "@(#) $Header$ (LBL)";
+ #endif
+ 
+ #ifdef HAVE_CONFIG_H
+ #include "config.h"
+ #endif
+ 
+ #include <sys/param.h>                        /* optionally get BSD define */
+ 
+ #include <stdlib.h>
+ #include <string.h>
+ #include <errno.h>
+ 
+ #include "pcap-int.h"
+ 
+ #include <sys/mman.h>
+ #include <sys/socket.h>
+ 
+ struct mbuf;          /* Squelch compiler warnings on some platforms for */
+ struct rtentry;               /* declarations in <net/if.h> */
+ #include <net/if.h>
+ 
+ #include <dagnew.h>
+ #include <dagapi.h>
+ 
+ typedef struct pcap_dag_node {
+   struct pcap_dag_node *next;
+   pcap_t *p;
+ } pcap_dag_node_t;
+ 
+ static pcap_dag_node_t *pcap_dags = NULL;
+ static int atexit_handler_installed = 0;
+ 
+ #ifdef DAG_ONLY
+ /* This code is reguired when compiling for a DAG device only. */
+ #include "pcap-dag.h"
+ 
+ /* Replace dag function names with pcap equivalent. */
+ #define dag_stats pcap_stats
+ #define dag_read pcap_read
+ #define dag_open_live pcap_open_live
+ #define dag_platform_finddevs pcap_platform_finddevs
+ #define dag_setfilter pcap_setfilter
+ #define dag_set_datalink_platform pcap_set_datalink_platform
+ #define dag_platform_close pcap_platform_close
+ #endif /* DAG_ONLY */
+ 
+ static void delete_pcap_dag(pcap_t *p) {
+   pcap_dag_node_t *curr = NULL, *prev = NULL;
+ 
+   for (prev = NULL, curr = pcap_dags;
+       curr != NULL && curr->p != p;
+       prev = curr, curr = curr->next) {
+     /* empty */
+   }
+ 
+   if (curr != NULL && curr->p == p) {
+     if (prev != NULL) {
+       prev->next = curr->next;
+     } else {
+       pcap_dags = curr->next;
+     }
+   }
+ }
+ 
+ /*
+  * Performs a graceful shutdown of the DAG card and frees dynamic memory held
+  * in the pcap_t structure.
+  */
+ 
+ void dag_platform_close(pcap_t *p) {
+ 
+ #ifdef linux
+   if (p != NULL && p->md.is_dag && p->md.device != NULL) {
+     if(dag_stop(p->fd) < 0)
+       fprintf(stderr,"dag_stop %s: %s\n", p->md.device, strerror(errno));
+     if(dag_close(p->fd) < 0)
+       fprintf(stderr,"dag_close %s: %s\n", p->md.device, strerror(errno));
+     
+     free(p->md.device);
+   }
+ #else
+   if (p != NULL && p->md.is_dag) {
+     if(dag_stop(p->fd) < 0)
+       fprintf(stderr,"dag_stop: %s\n", strerror(errno));
+     if(dag_close(p->fd) < 0)
+       fprintf(stderr,"dag_close: %s\n", strerror(errno));
+   }
+ #endif
+   delete_pcap_dag(p);
+ }
+ 
+ static void atexit_handler(void) {
+   while (pcap_dags != NULL) {
+     dag_platform_close(pcap_dags->p);
+   }
+ }
+ 
+ static int new_pcap_dag(pcap_t *p) {
+   pcap_dag_node_t *node = NULL;
+ 
+   if ((node = malloc(sizeof(pcap_dag_node_t))) == NULL) {
+     return -1;
+   }
+ 
+   if (!atexit_handler_installed) {
+     atexit(atexit_handler);
+     atexit_handler_installed = 1;
+   }
+ 
+   node->next = pcap_dags;
+   node->p = p;
+ 
+   return 0;
+ }
+ 
+ /*
+  * Get pointer to the ERF header for the next packet in the input
+  * stream. This function blocks until a packet becomes available.
+  */
+ static dag_record_t *get_next_dag_header(pcap_t *p) {
+   register dag_record_t *record;
+   int rlen;
+ 
+   if (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size) {
+     p->md.dag_mem_top = dag_offset(p->fd, &(p->md.dag_mem_bottom), 0);
+   }
+ 
+   record = (dag_record_t *)(p->md.dag_mem_base + p->md.dag_mem_bottom);
+   rlen = ntohs(record->rlen);
+   while (p->md.dag_mem_top - p->md.dag_mem_bottom < rlen) {
+     p->md.dag_mem_top = dag_offset(p->fd, &(p->md.dag_mem_bottom), 0);
+     record = (dag_record_t *)(p->md.dag_mem_base + p->md.dag_mem_bottom);
+     rlen = ntohs(record->rlen);
+   }
+ 
+   p->md.dag_mem_bottom += rlen;
+   
+   return record;
+ }
+ 
+ /* Size of payload in ATM packets */
+ #define ATM_CAPTURE_SIZE 48
+ 
+ /* Size of payload of Ethernet packet */
+ #define ETHERNET_LENGTH(h) min(ntohs((h)->wlen) - 4, ntohs((h)->rlen) - dag_record_size - 2 - (ntohs((h)->wlen) & 
0x3))
+ 
+ /* Size of HDLC packet */
+ #define HDLC_LENGTH(h) min(ntohs((h)->wlen) - 4, ntohs((h)->rlen) - dag_record_size)
+ 
+ #ifndef min
+ #define min(a, b) ((a) > (b) ? (b) : (a))
+ #endif
+ 
+ /*
+  * Swap byte ordering of unsigned long long on a big endian
+  * machine.
+  */
+ static unsigned long long swapll(unsigned long long ull) {
+ #if (BYTE_ORDER == BIG_ENDIAN)
+   return ((ull & 0xff00000000000000LL) >> 56) |
+     ((ull & 0x00ff000000000000LL) >> 40) |
+     ((ull & 0x0000ff0000000000LL) >> 24) |
+     ((ull & 0x000000ff00000000LL) >>  8) |
+     ((ull & 0x00000000ff000000LL) <<  8) |
+     ((ull & 0x0000000000ff0000LL) << 24) |
+     ((ull & 0x000000000000ff00LL) << 40) |
+     ((ull & 0x00000000000000ffLL) << 56) ;
+ #else
+   return ull;
+ #endif
+ }
+ 
+ /*
+  *  Read at most max_packets from the capture stream and call the callback
+  *  for each of them. Returns the number of packets handled or -1 if an
+  *  error occured.  A blocking 
+  */
+ int dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) {
+   u_char              *dp = NULL;
+   int                 packet_len = 0, caplen = 0;
+   struct pcap_pkthdr  pcap_header;
+ 
+   dag_record_t *header;
+   register unsigned long long ts;
+  
+   /* Receive a single packet from the kernel */
+   header = get_next_dag_header(p);
+   dp = ((u_char *)header) + dag_record_size;
+ 
+   switch(header->type) {
+   case TYPE_ATM:
+     packet_len = ATM_CAPTURE_SIZE;
+     caplen = ATM_CAPTURE_SIZE;
+     break;
+   case TYPE_ETH:
+     packet_len = ntohs(header->wlen);
+     caplen = ETHERNET_LENGTH(header);
+     dp += 2;
+     break;
+   case TYPE_HDLC_POS:
+     packet_len = ntohs(header->wlen);
+     caplen = HDLC_LENGTH(header);
+     break;
+   }
+  
+   if (caplen > p->snapshot)
+     caplen = p->snapshot;
+ 
+   /* Run the packet filter if not using kernel filter */
+   if (p->fcode.bf_insns) {
+     if (bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen) == 0) {
+       /* rejected by filter */
+       return 0;
+     }
+   }
+ 
+   // convert between timestamp formats
+   ts = swapll(header->ts);
+   pcap_header.ts.tv_sec  = ts >> 32;
+   ts = ((ts &  0xffffffffULL) * 1000 * 1000);
+   ts += (ts & 0x80000000ULL) << 1; /* rounding */
+   pcap_header.ts.tv_usec = ts >> 32;          
+   if (pcap_header.ts.tv_usec >= 1000000) {
+     pcap_header.ts.tv_usec -= 1000000;
+     pcap_header.ts.tv_sec += 1;
+   }
+ 
+   /* Fill in our own header data */
+   pcap_header.caplen = caplen;
+   pcap_header.len = packet_len;
+   
+   /*
+    * Count the packet.
+    */
+   p->md.stat.ps_recv++;
+   
+   /* Call the user supplied callback function */
+   callback(user, &pcap_header, dp);
+   
+   return 1;
+ }
+ 
+ /*
+  *  Get a handle for a live capture from the given DAG device.  Passing a NULL
+  *  device will result in a failure.  The promisc flag is ignored becuase DAG
+  *  cards are always promiscuous.  The to_ms parameter is also ignored as it is
+  *  not supported in hardware.
+  *  
+  *  See also pcap(3).
+  */
+ pcap_t *dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf) {
+   char conf[30]; /* dag configure string */
+   pcap_t *handle;
+   
+   if (device == NULL) {
+     snprintf(ebuf, PCAP_ERRBUF_SIZE, "device is NULL: %s", pcap_strerror(errno));
+     return NULL;
+   }
+   /* Allocate a handle for this session. */
+ 
+   handle = malloc(sizeof(*handle));
+   if (handle == NULL) {
+     snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc %s: %s", device, pcap_strerror(errno));
+     return NULL;
+   }
+   
+   /* Initialize some components of the pcap structure. */
+   
+   memset(handle, 0, sizeof(*handle));
+ 
+   if (strstr(device, "/dev") == NULL) {
+     char * newDev = (char *)malloc(strlen(device) + 6);
+     newDev[0] = '\0';
+     strcat(newDev, "/dev/");
+     strcat(newDev,device);
+     device = newDev;
+   }
+ 
+   /* setup device parameters */
+   if((handle->fd = dag_open((char *)device)) < 0) {
+     snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_open %s: %s", device, pcap_strerror(errno));
+     return NULL;
+   }
+ 
+   /* set the card snap length as specified by the specified snaplen parameter */
+   snprintf(conf, 30, "varlen slen=%d", (snaplen % 4) ? (snaplen + 3) & ~3 : snaplen); // snap len has to be a 
multiple of 4
+   fprintf(stderr, "Configuring DAG with '%s'.\n", conf);
+   if(dag_configure(handle->fd, conf) < 0) {
+     snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_configure %s: %s\n", device, pcap_strerror(errno));
+     return NULL;
+   }
+   
+   if((handle->md.dag_mem_base = dag_mmap(handle->fd)) == MAP_FAILED) {
+     snprintf(ebuf, PCAP_ERRBUF_SIZE,"dag_mmap %s: %s\n", device, pcap_strerror(errno));
+     return NULL;
+   }
+   
+   if(dag_start(handle->fd) < 0) {
+     snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, pcap_strerror(errno));
+     return NULL;
+   }
+ 
+   /*
+    * Important! You have to ensure bottom is properly
+    * initialized to zero on startup, it won't give you
+    * a compiler warning if you make this mistake!
+    */
+   handle->md.dag_mem_bottom = 0;
+   handle->md.dag_mem_top = 0;
+   handle->md.is_dag = 1;
+ 
+   handle->snapshot    = snaplen;
+   //handle->md.timeout        = to_ms;
+ 
+ #ifdef linux
+   if (device) {
+     handle->md.device = strdup(device);
+   }
+ 
+   if (handle->md.device == NULL) {
+     snprintf(ebuf, PCAP_ERRBUF_SIZE, "str_dup %s: %s\n", device, pcap_strerror(errno));
+     free(handle);
+     return NULL;
+   }
+ #endif
+ 
+   /* set link type */
+   
+   /* Check the type through a dagapi call.
+   */
+   switch(dag_linktype(handle->fd)) {
+   case TYPE_HDLC_POS:
+     handle->linktype = DLT_CHDLC;
+     fprintf(stderr, "Set DAG linktype to %d (DLT_CHDLC)\n", handle->linktype);
+     break;
+   case TYPE_ETH:
+     handle->linktype = DLT_EN10MB;
+     fprintf(stderr, "Set DAG linktype to %d (DLT_EN10MB)\n", handle->linktype);
+     break;
+   case TYPE_ATM: 
+     handle->linktype = DLT_ATM_RFC1483;
+     fprintf(stderr, "Set DAG linktype to %d (DLT_ATM_RFC1483)\n", handle->linktype);
+     break;
+   case TYPE_LEGACY:
+     handle->linktype = DLT_NULL;
+     fprintf(stderr, "Set DAG linktype to %d (DLT_NULL)\n", handle->linktype);
+     break;
+   default:
+     snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_open_live %s: unknown linktype %d\n", device, dag_linktype(handle->fd));
+     return NULL;
+   }
+   
+   handle->bufsize = 0;//handle->snapshot;
+ 
+   if (new_pcap_dag(handle) < 0) {
+     snprintf(ebuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, pcap_strerror(errno));
+     return NULL;
+   }
+ 
+   return handle;
+ }
+ 
+ int dag_stats(pcap_t *p, struct pcap_stat *ps) {
+   /* This needs to be filled out correctly.  Hopefully a dagapi call will
+      provide all necessary information.
+   */
+   //p->md.stat.ps_recv = 0;
+   //p->md.stat.ps_drop = 0;
+   
+   *ps = p->md.stat;
+  
+   return 0;
+ }
+ 
+ /*
+  * Get from "/proc/dag" all interfaces listed there; if they're
+  * already in the list of interfaces we have, that won't add another
+  * instance, but if they're not, that'll add them.
+  *
+  * We don't bother getting any addresses for them.
+  *
+  * We also don't fail if we couldn't open "/proc/dag"; we just leave
+  * the list of interfaces as is.
+  */
+ int
+ dag_platform_finddevs(pcap_if_t **devlistp, char *errbuf)
+ {
+   FILE *proc_dag_f;
+   char linebuf[512];
+   int linenum;
+   unsigned char *p;
+   char name[512];     /* XXX - pick a size */
+   char *q, *saveq;
+   struct ifreq ifrflags;
+   int ret = 0;
+ 
+   /* Quick exit if /proc/dag not readable */
+   proc_dag_f = fopen("/proc/dag", "r");
+   if (proc_dag_f == NULL)
+   {
+     int i, fd;
+     char dev[16] = "dagx";
+ 
+     for (i = '0'; ret == 0 && i <= '9'; i++) {
+       dev[3] = i;
+       if (pcap_add_if(devlistp, dev, 0, NULL, errbuf) == -1) {
+         /*
+          * Failure.
+          */
+         ret = -1;
+       }
+     }
+           
+     return (ret);
+   }
+ 
+   for (linenum = 1;
+         fgets(linebuf, sizeof linebuf, proc_dag_f) != NULL; linenum++) {
+     
+     /*
+      * Skip the first two lines - they're headers.
+      */
+     if (linenum <= 2)
+       continue;
+ 
+     p = &linebuf[0];
+ 
+     if (*p == '\0' || *p == '\n' || *p != 'D')
+       continue;  /* not a Dag line */
+ 
+     /*
+      * Get the interface name.
+      */
+     q = &name[0];
+     while (*p != '\0' && *p != ':') {
+       if (*p != ' ')
+         *q++ = tolower(*p++);
+       else
+         p++;
+     }
+     *q = '\0';
+ 
+     /*
+      * Add an entry for this interface, with no addresses.
+      */
+     p[strlen(p) - 1] = '\0'; /* get rid of \n */
+     if (pcap_add_if(devlistp, name, 0, strdup(p + 2), errbuf) == -1) {
+       /*
+        * Failure.
+        */
+       ret = -1;
+       break;
+     }
+   }
+   if (ret != -1) {
+     /*
+      * Well, we didn't fail for any other reason; did we
+      * fail due to an error reading the file?
+      */
+     if (ferror(proc_dag_f)) {
+       (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
+           "Error reading /proc/dag: %s",
+           pcap_strerror(errno));
+       ret = -1;
+     }
+   }
+ 
+   (void)fclose(proc_dag_f);
+   return (ret);
+ }
+ 
+ /*
+  * Installs the gven bpf filter program in the given pcap structure.  There is
+  * no attempt to store the filter in kernel memory as that is not supported
+  * with DAG cards.
+  */
+ int dag_setfilter(pcap_t *p, struct bpf_program *fp) {
+   if (!p)
+     return -1;
+   if (!fp) {
+     strncpy(p->errbuf, "setfilter: No filter specified",
+           sizeof(p->errbuf));
+     return -1;
+   }
+ 
+   /* Make our private copy of the filter */
+ 
+   if (install_bpf_program(p, fp) < 0) {
+     snprintf(p->errbuf, sizeof(p->errbuf),
+            "malloc: %s", pcap_strerror(errno));
+     return -1;
+   }
+ 
+   p->md.use_bpf = 0;
+ 
+   return (0);
+ }
+ 
+ int
+ dag_set_datalink_platform(pcap_t *p, int dlt)
+ {
+       return (0);
+ }
diff -c --unidirectional-new-file libpcap-current/pcap-dag.h libpcap/pcap-dag.h
*** libpcap-current/pcap-dag.h  Thu Jan  1 12:00:00 1970
--- libpcap/pcap-dag.h  Tue May 20 15:37:22 2003
***************
*** 0 ****
--- 1,18 ----
+ /*
+  * pcap-dag.c: Packet capture interface for Endace DAG card.
+  *
+  * The functionality of this code attempts to mimic that of pcap-linux as much
+  * as possible.  This code is only needed when compiling in the DAG card code
+  * at the same time as another type of device.
+  *
+  * Author: Richard Littin, Sean Irvine ({richard,sean}@reeltwo.com)
+  *
+  * @(#) $Header$ (LBL)
+  */
+ 
+ int dag_stats(pcap_t *p, struct pcap_stat *ps);
+ int dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
+ pcap_t *dag_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf);
+ int dag_setfilter(pcap_t *p, struct bpf_program *fp);
+ void dag_platform_close(pcap_t *p);
+ 
diff -c --unidirectional-new-file libpcap-current/pcap-int.h libpcap/pcap-int.h
*** libpcap-current/pcap-int.h  Thu May 22 15:25:34 2003
--- libpcap/pcap-int.h  Mon May 12 10:32:25 2003
***************
*** 76,81 ****
--- 76,88 ----
        char    *device;        /* device name */
        struct pcap *next;      /* list of open promiscuous sock_packet pcaps */
  #endif
+ 
+ #ifdef HAVE_DAG_API
+       int     is_dag;         /* this is a dag card handle */
+       void    *dag_mem_base;  /* DAG card memory base address */
+       u_int   dag_mem_bottom; /* DAG card current memory bottom pointer */
+       u_int   dag_mem_top;    /* DAG card current memory top pointer */
+ #endif
  };
  
  struct pcap {
diff -c --unidirectional-new-file libpcap-current/pcap-linux.c libpcap/pcap-linux.c
*** libpcap-current/pcap-linux.c        Thu May 22 15:25:35 2003
--- libpcap/pcap-linux.c        Thu May 22 10:08:47 2003
***************
*** 24,29 ****
--- 24,30 ----
   *  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   */
+ 
  #ifndef lint
  static const char rcsid[] =
      "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.89 2003/04/09 07:19:49 guy Exp $ (LBL)";
***************
*** 79,84 ****
--- 80,89 ----
  #include "pcap-int.h"
  #include "sll.h"
  
+ #ifdef HAVE_DAG_API
+ #include "pcap-dag.h"
+ #endif /* HAVE_DAG_API */
+         
  #include <errno.h>
  #include <stdlib.h>
  #include <unistd.h>
***************
*** 228,233 ****
--- 233,244 ----
        int             live_open_ok = 0;
        struct utsname  utsname;
  
+ #ifdef HAVE_DAG_API
+       if (strstr(device, "dag")) {
+               return dag_open_live(device, snaplen, promisc, to_ms, ebuf);
+       }
+ #endif /* HAVE_DAG_API */
+ 
          /* Allocate a handle for this session. */
  
        handle = malloc(sizeof(*handle));
***************
*** 403,408 ****
--- 414,425 ----
  int
  pcap_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
  {
+ #ifdef HAVE_DAG_API
+       if (handle->md.is_dag) {
+               return dag_read(handle, max_packets, callback, user);
+       }
+ #endif /* HAVE_DAG_API */
+ 
        /*
         * Currently, on Linux only one packet is delivered per read,
         * so we don't loop.
***************
*** 655,661 ****
--- 672,686 ----
  #ifdef HAVE_TPACKET_STATS
        struct tpacket_stats kstats;
        socklen_t len = sizeof (struct tpacket_stats);
+ #endif
+ 
+ #ifdef HAVE_DAG_API
+       if (handle->md.is_dag) {
+               return dag_stats(handle, stats);
+       }
+ #endif /* HAVE_DAG_API */
  
+ #ifdef HAVE_TPACKET_STATS
        /*
         * Try to get the packet counts from the kernel.
         */
***************
*** 748,753 ****
--- 773,783 ----
        if (pcap_add_if(alldevsp, "any", 0, any_descr, errbuf) < 0)
                return (-1);
  
+ #ifdef HAVE_DAG_API
+       if (dag_platform_finddevs(alldevsp, errbuf) < 0)
+               return (-1);
+ #endif /* HAVE_DAG_API */
+ 
        return (0);
  }
  
***************
*** 763,768 ****
--- 793,804 ----
        int                     err = 0;
  #endif
  
+ #ifdef HAVE_DAG_API
+       if (handle->md.is_dag) {
+               return dag_setfilter(handle, filter);
+       }
+ #endif /* HAVE_DAG_API */
+ 
        if (!handle)
                return -1;
        if (!filter) {
***************
*** 1428,1433 ****
--- 1464,1476 ----
        struct pcap     *p, *prevp;
        struct ifreq    ifr;
  
+ #ifdef HAVE_DAG_API
+       if (handle->md.is_dag) {
+               /* close actions will be done in dag_platform_close() */
+               return;
+       }
+ #endif /* HAVE_DAG_API */
+ 
        if (handle->md.clear_promisc) {
                /*
                 * We put the interface into promiscuous mode; take
***************
*** 1950,1954 ****
--- 1993,2003 ----
  int
  pcap_set_datalink_platform(pcap_t *p, int dlt)
  {
+ #ifdef HAVE_DAG_API
+       if (p->md.is_dag) {
+               return dag_set_datalink_platform(p, dlt);
+       }
+ #endif /* HAVE_DAG_API */
+ 
        return (0);
  }
diff -c --unidirectional-new-file libpcap-current/pcap.c libpcap/pcap.c
*** libpcap-current/pcap.c      Thu May 22 15:25:38 2003
--- libpcap/pcap.c      Mon May 12 10:31:38 2003
***************
*** 638,643 ****
--- 638,646 ----
  #ifdef linux
                pcap_close_linux(p);
  #endif
+ #ifdef HAVE_DAG_API
+               dag_platform_close(p);
+ #endif
                close(p->fd);
        }
  #else /* WIN32 */

Current thread: