Hi all,

This patch contains a number of improvements for libpcap's support for
Endace DAG cards:

* Much improved performance.  Previously the read operation would only ever
retrieve and process 1 packet, even if asked for a bufferful, which added a
large amount of overhead.
* Support for nonblocking operation.
* Miscellaneous bug/portability fixes.

Cheers,
Koryn
-- 
Dr Koryn Grant                         phone   +64 7 8346729
Senior Software Engineer               mobile  +64 21 488386
Endace Technology Ltd                  email   [EMAIL PROTECTED]
Hamilton, New Zealand                  web     http://www.endace.com/
Only in libpcap-mod: .#pcap-dag.c.1.10
Only in libpcap-mod: .#pcap.c.1.63
Only in libpcap-mod: .#pcap.c.1.64
Common subdirectories: libpcap/CVS and libpcap-mod/CVS
Common subdirectories: libpcap/SUNOS4 and libpcap-mod/SUNOS4
Common subdirectories: libpcap/Win32 and libpcap-mod/Win32
Common subdirectories: libpcap/bpf and libpcap-mod/bpf
Common subdirectories: libpcap/lbl and libpcap-mod/lbl
Only in libpcap-mod: net
Common subdirectories: libpcap/packaging and libpcap-mod/packaging
diff -ubB libpcap/pcap-dag.c libpcap-mod/pcap-dag.c
--- libpcap/pcap-dag.c  Wed Nov 19 11:55:16 2003
+++ libpcap-mod/pcap-dag.c      Wed Nov 19 09:53:38 2003
@@ -15,6 +15,16 @@
  *   2003 May - Jesper Peterson <[EMAIL PROTECTED]>
  *              Code shuffled around to suit fad-xxx.c structure
  *              Added atexit() handler to stop DAG if application is too lazy
+ *   2003 September - Koryn Grant <[EMAIL PROTECTED]>
+ *              Added support for nonblocking operation.
+ *              Added support for processing more than a single packet in 
pcap_dispatch().
+ *              Fixed bug in loss counter code.
+ *              Improved portability of loss counter code (e.g. use UINT_MAX instead 
of 0xffff).
+ *              Removed unused local variables.
+ *              Added required headers (ctype.h, limits.h, unistd.h, netinet/in.h).
+ *   2003 October - Koryn Grant <[EMAIL PROTECTED]>
+ *              Changed semantics to match those of standard pcap on linux.
+ *                - packets rejected by the filter are not counted.
  */
 
 #ifndef lint
@@ -34,8 +44,12 @@
 
 #include "pcap-int.h"
 
+#include <ctype.h>
+#include <netinet/in.h>
 #include <sys/mman.h>
 #include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 struct mbuf;           /* Squelch compiler warnings on some platforms for */
 struct rtentry;                /* declarations in <net/if.h> */
@@ -44,28 +58,10 @@
 #include <dagnew.h>
 #include <dagapi.h>
 
-#ifndef min
-#define min(a, b) ((a) > (b) ? (b) : (a))
-#endif
-
 #define MIN_DAG_SNAPLEN                12
 #define MAX_DAG_SNAPLEN                2040
 #define ATM_SNAPLEN            48
 
-/* Size of ATM payload */
-#define ATM_WLEN(h)            ATM_SNAPLEN
-#define ATM_SLEN(h)            ATM_SNAPLEN
-
-/* Size Ethernet payload */
-#define ETHERNET_WLEN(h, b)    (ntohs((h)->wlen) - ((b) >> 3))
-#define ETHERNET_SLEN(h, b)    min(ETHERNET_WLEN(h, b), \
-                                   ntohs((h)->rlen) - dag_record_size - 2)
-
-/* Size of HDLC payload */
-#define HDLC_WLEN(h, b)                (ntohs((h)->wlen) - ((b) >> 3))
-#define HDLC_SLEN(h, b)                min(HDLC_WLEN(h, b), \
-                                   ntohs((h)->rlen) - dag_record_size)
-
 typedef struct pcap_dag_node {
   struct pcap_dag_node *next;
   pcap_t *p;
@@ -74,7 +70,7 @@
 
 static pcap_dag_node_t *pcap_dags = NULL;
 static int atexit_handler_installed = 0;
-static unsigned short endian_test_word = 0x0100;
+static const unsigned short endian_test_word = 0x0100;
 
 #define IS_BIGENDIAN() (*((unsigned char *)&endian_test_word))
 
@@ -82,19 +78,18 @@
  * Swap byte ordering of unsigned long long timestamp on a big endian
  * machine.
  */
-#define SWAP_TS(ull)  \
-    (IS_BIGENDIAN() ? ((ull & 0xff00000000000000LL) >> 56) | \
+#define SWAP_TS(ull)  ((ull & 0xff00000000000000LL) >> 56) | \
                       ((ull & 0x00ff000000000000LL) >> 40) | \
                       ((ull & 0x0000ff0000000000LL) >> 24) | \
                       ((ull & 0x000000ff00000000LL) >> 8)  | \
                       ((ull & 0x00000000ff000000LL) << 8)  | \
                       ((ull & 0x0000000000ff0000LL) << 24) | \
                       ((ull & 0x000000000000ff00LL) << 40) | \
-                      ((ull & 0x00000000000000ffLL) << 56) \
-                    : ull)
+                      ((ull & 0x00000000000000ffLL) << 56)
+
 
 #ifdef DAG_ONLY
-/* This code is reguired when compiling for a DAG device only. */
+/* This code is required when compiling for a DAG device only. */
 #include "pcap-dag.h"
 
 /* Replace dag function names with pcap equivalent. */
@@ -150,6 +145,7 @@
   }
 #endif
   delete_pcap_dag(p);
+  /* Note: don't need to call close(p->fd) here as dag_close(p->fd) does this. */
 }
 
 static void atexit_handler(void) {
@@ -184,122 +180,155 @@
 }
 
 /*
- * 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;
-
-  /*
-   * The buffer is guaranteed to only contain complete records so any
-   * time top and bottom differ there will be at least one record available.
-   * Here we test the difference is at least the size of a record header
-   * using the poorly named constant 'dag_record_size'.
+ *  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.
    */
-  while ((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);
-  }
+static int dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) {
+       unsigned int processed = 0;
+       int flags = p->md.dag_offset_flags;
+       unsigned int nonblocking = flags & DAGF_NONBLOCK;
 
-  record = (dag_record_t *)(p->md.dag_mem_base + p->md.dag_mem_bottom);
+       for (;;)
+       {
+               /* Get the next bufferful of packets (if necessary). */
+               while (p->md.dag_mem_top - p->md.dag_mem_bottom < dag_record_size) {
 
-  p->md.dag_mem_bottom += ntohs(record->rlen);
+                       p->md.dag_mem_top = dag_offset(p->fd, &(p->md.dag_mem_bottom), 
flags);
+                       if ((p->md.dag_mem_top - p->md.dag_mem_bottom < 
dag_record_size) && nonblocking)
+                       {
+                               /* Pcap is configured to process only available 
packets, and there aren't any. */
+                               return 0;
+                       }
+               }
   
-  return record;
-}
+               /* Process the packets. */
+               while (p->md.dag_mem_top - p->md.dag_mem_bottom >= dag_record_size) {
 
-/*
- *  Read at most max_packets from the capture stream and call the callback
- *  for each of them. Returns the number of packets handled, -1 if an
- *  error occured, or -2 if we were told to break out of the loop.
- *  A blocking 
- */
-static int dag_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) {
-  u_char               *dp = NULL;
-  int                  packet_len = 0, caplen = 0;
+                       unsigned short packet_len = 0;
+                       int caplen = 0;
   struct pcap_pkthdr   pcap_header;
 
-  dag_record_t *header;
-  register unsigned long long ts;
+                       dag_record_t *header = (dag_record_t *)(p->md.dag_mem_base + 
p->md.dag_mem_bottom);
+                       u_char *dp = ((u_char *)header) + dag_record_size;
+                       unsigned short rlen;
  
-  /*
-   * Has "pcap_breakloop()" been called?
-   */
-  if (p->break_loop) {
-    /*
-     * Yes - clear the flag that indicates that it has, and return -2
-     * to indicate that we were told to break out of the loop.
-     */
-    p->break_loop = 0;
-    return -2;
+                       if (IS_BIGENDIAN())
+                       {
+                               rlen = header->rlen;
   }
-
-  /* Receive a single packet from the kernel */
-  header = get_next_dag_header(p);
-  dp = ((u_char *)header) + dag_record_size;
+                       else
+                       {
+                               rlen = ntohs(header->rlen);
+                       }
+                       p->md.dag_mem_bottom += rlen;
 
   switch(header->type) {
   case TYPE_ATM:
-    packet_len = ATM_WLEN(header);
-    caplen = ATM_SLEN(header);
+                               packet_len = ATM_SNAPLEN;
+                               caplen = ATM_SNAPLEN;
     dp += 4;
     break;
+
   case TYPE_ETH:
-    packet_len = ETHERNET_WLEN(header, p->md.dag_fcs_bits);
-    caplen = ETHERNET_SLEN(header, p->md.dag_fcs_bits);
+                               if (IS_BIGENDIAN())
+                               {
+                                       packet_len = header->wlen;
+                               }
+                               else
+                               {
+                                       packet_len = ntohs(header->wlen);
+                               }
+                               packet_len -= (p->md.dag_fcs_bits >> 3);
+                               caplen = rlen - dag_record_size - 2;
+                               if (caplen > packet_len)
+                               {
+                                       caplen = packet_len;
+                               }
     dp += 2;
     break;
+
   case TYPE_HDLC_POS:
-    packet_len = HDLC_WLEN(header, p->md.dag_fcs_bits);
-    caplen = HDLC_SLEN(header, p->md.dag_fcs_bits);
+                               if (IS_BIGENDIAN())
+                               {
+                                       packet_len = header->wlen;
+                               }
+                               else
+                               {
+                                       packet_len = ntohs(header->wlen);
+                               }
+                               packet_len -= (p->md.dag_fcs_bits >> 3);
+                               caplen = rlen - dag_record_size;
+                               if (caplen > packet_len)
+                               {
+                                       caplen = packet_len;
+                               }
     break;
   }
  
   if (caplen > p->snapshot)
     caplen = p->snapshot;
 
-  /* Count lost packets */
-  if (header->lctr > 0 && (p->md.stat.ps_drop+1) != 0) {
-    if (header->lctr == 0xffff ||
-       (p->md.stat.ps_drop + header->lctr) < p->md.stat.ps_drop) {
-      p->md.stat.ps_drop == ~0;
+                       /* Count lost packets. */
+                       if (header->lctr) {
+                               if (p->md.stat.ps_drop > (UINT_MAX - header->lctr)) {
+                                       p->md.stat.ps_drop = UINT_MAX;
     } else {
       p->md.stat.ps_drop += header->lctr;
     }
   }
 
-  /* 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;
-    }
-  }
+                       /* Run the packet filter if there is one. */
+                       if ((p->fcode.bf_insns == NULL) || 
bpf_filter(p->fcode.bf_insns, dp, packet_len, caplen)) {
 
   /* convert between timestamp formats */
+                               register unsigned long long ts;
+                               
+                               if (IS_BIGENDIAN())
+                               {
   ts = SWAP_TS(header->ts);
+                               }
+                               else
+                               {
+                                       ts = header->ts;
+                               }
+
   pcap_header.ts.tv_sec  = ts >> 32;
-  ts = ((ts &  0xffffffffULL) * 1000 * 1000);
-  ts += (ts & 0x80000000ULL) << 1; /* rounding */
+                               ts = (ts & 0xffffffffULL) * 1000000;
+                               ts += 0x80000000; /* 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;
+                                       pcap_header.ts.tv_sec++;
   }
 
   /* Fill in our own header data */
   pcap_header.caplen = caplen;
   pcap_header.len = packet_len;
   
-  /*
-   * Count the packet.
-   */
+                               /* Count the packet. */
   p->md.stat.ps_recv++;
   
   /* Call the user supplied callback function */
   callback(user, &pcap_header, dp);
   
-  return 1;
+                               /* Only count packets that pass the filter, for 
consistency with standard Linux behaviour. */
+                               processed++;
+                               if (processed == cnt)
+                               {
+                                       /* Reached the user-specified limit. */
+                                       return cnt;
+                               }
+                       }
+               }
+
+               if (nonblocking || processed)
+               {
+                       return processed;
+               }
+       }
+  
+       return processed;
 }
 
 /*
@@ -338,19 +367,25 @@
     strcat(newDev, "/dev/");
     strcat(newDev,device);
     device = newDev;
+  } else {
+       device = strdup(device);
+  }
+
+  if (device == NULL) {
+       snprintf(ebuf, PCAP_ERRBUF_SIZE, "str_dup: %s\n", pcap_strerror(errno));
+       goto fail;
   }
 
   /* 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;
+    goto fail;
   }
 
-  /* set the card snap length as specified by the specified snaplen parameter */
+  /* set the card snap length to the specified snaplen parameter */
   if (snaplen == 0 || snaplen > MAX_DAG_SNAPLEN) {
     snaplen = MAX_DAG_SNAPLEN;
-  } else
-  if (snaplen < MIN_DAG_SNAPLEN) {
+  } else if (snaplen < MIN_DAG_SNAPLEN) {
     snaplen = MIN_DAG_SNAPLEN;
   }
   /* snap len has to be a multiple of 4 */
@@ -359,17 +394,17 @@
   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;
+    goto fail;
   }
   
   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;
+    goto fail;
   }
   
   if(dag_start(handle->fd) < 0) {
     snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_start %s: %s\n", device, 
pcap_strerror(errno));
-    return NULL;
+    goto fail;
   }
 
   /*
@@ -388,37 +423,32 @@
     } else {
       snprintf(ebuf, PCAP_ERRBUF_SIZE,
         "pcap_open_live %s: bad ERF_FCS_BITS value (%d) in environment\n", device, n);
-      return NULL;
+      goto fail;
     }
   }
 
   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
-
   if ((handle->linktype = dag_get_datalink(handle)) < 0) {
     snprintf(ebuf, PCAP_ERRBUF_SIZE, "dag_get_linktype %s: unknown linktype\n", 
device);
-    return NULL;
+       goto fail;
   }
   
   handle->bufsize = 0;
 
   if (new_pcap_dag(handle) < 0) {
     snprintf(ebuf, PCAP_ERRBUF_SIZE, "new_pcap_dag %s: %s\n", device, 
pcap_strerror(errno));
-    return NULL;
+       goto fail;
   }
 
+#ifdef linux
+  handle->md.device = (char *)device;
+#else
+  free((char *)device);
+  device = NULL;
+#endif
+
   handle->read_op = dag_read;
   handle->setfilter_op = dag_setfilter;
   handle->set_datalink_op = dag_set_datalink;
@@ -426,6 +456,16 @@
   handle->close_op = dag_platform_close;
 
   return handle;
+
+fail:
+  if (device != NULL) {
+       free((char *)device);
+  }
+  if (handle != NULL) {
+       free(handle);
+  }
+
+  return NULL;
 }
 
 static int dag_stats(pcap_t *p, struct pcap_stat *ps) {
@@ -458,15 +498,14 @@
   int linenum;
   unsigned char *p;
   char name[512];      /* XXX - pick a size */
-  char *q, *saveq;
-  struct ifreq ifrflags;
+  char *q;
   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;
+    int i;
     char dev[16] = "dagx";
 
     for (i = '0'; ret == 0 && i <= '9'; i++) {
@@ -538,7 +577,7 @@
 }
 
 /*
- * Installs the gven bpf filter program in the given pcap structure.  There is
+ * Installs the given 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.
  */
diff -ubB libpcap/pcap-int.h libpcap-mod/pcap-int.h
--- libpcap/pcap-int.h  Tue Nov  4 20:05:34 2003
+++ libpcap-mod/pcap-int.h      Fri Nov  7 12:29:45 2003
@@ -89,6 +89,7 @@
        u_int   dag_mem_bottom; /* DAG card current memory bottom pointer */
        u_int   dag_mem_top;    /* DAG card current memory top pointer */
        int     dag_fcs_bits;   /* Number of checksum bits from link layer */
+       int dag_offset_flags; /* Flags to pass to dag_offset(). */
 #endif
 };
 
diff -ubB libpcap/pcap.c libpcap-mod/pcap.c
--- libpcap/pcap.c      Wed Nov 19 11:55:19 2003
+++ libpcap-mod/pcap.c  Wed Nov 19 11:58:24 2003
@@ -61,6 +61,11 @@
 
 #include "pcap-int.h"
 
+#ifdef HAVE_DAG_API
+#include <dagnew.h>
+#include <dagapi.h>
+#endif
+
 int
 pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
 {
@@ -558,6 +564,15 @@
                 */
                return (0);
        }
+
+#if HAVE_DAG_API
+       if (nonblock) {
+               p->md.dag_offset_flags |= DAGF_NONBLOCK;
+       } else {
+               p->md.dag_offset_flags &= ~DAGF_NONBLOCK;
+       }
+#endif /* HAVE_DAG_API */
+
 #ifndef WIN32
        fdflags = fcntl(p->fd, F_GETFL, 0);
        if (fdflags == -1) {

Reply via email to