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 * Code shuffled around to suit fad-xxx.c structure * Added atexit() handler to stop DAG if application is too lazy + * 2003 September - Koryn Grant + * 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 + * 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 +#include #include #include +#include +#include struct mbuf; /* Squelch compiler warnings on some platforms for */ struct rtentry; /* declarations in */ @@ -44,28 +58,10 @@ #include #include -#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 +#include +#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) {