diff -urp libpcap-0.8.1.orig/pcap-bpf.c libpcap-0.8.1/pcap-bpf.c --- libpcap-0.8.1.orig/pcap-bpf.c 2003-11-22 00:06:28.000000000 +0000 +++ libpcap-0.8.1/pcap-bpf.c 2004-01-06 01:08:06.777209896 +0000 @@ -142,6 +142,8 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_h int cc; int n = 0; register u_char *bp, *ep; + struct pcap_pkthdr *pcap_header; + struct bpf_insn *fcode; fcode = p->md.use_bpf ? NULL : p->fcode.bf_insns; @@ -273,7 +275,16 @@ pcap_read_bpf(pcap_t *p, int cnt, pcap_h /* * XXX A bpf_hdr matches a pcap_pkthdr. */ - (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen); + pcap_header = pcap_header_new(p); + if ( ! pcap_header ) + return -1; + + pcap_header->ts.tv_sec = bhp->bh_tstamp.tv_sec; + pcap_header->ts.tv_usec = bhp->bh_tstamp.tv_usec; + pcap_header->caplen = caplen; + pcap_header->len = bhp->bh_datalen; + + (*callback)(user, pcap_header, bp + hdrlen); bp += BPF_WORDALIGN(caplen + hdrlen); if (++n >= cnt && cnt > 0) { p->bp = bp; diff -urp libpcap-0.8.1.orig/pcap-dag.c libpcap-0.8.1/pcap-dag.c --- libpcap-0.8.1.orig/pcap-dag.c 2003-11-21 10:20:45.000000000 +0000 +++ libpcap-0.8.1/pcap-dag.c 2004-01-06 00:45:05.813148344 +0000 @@ -221,7 +221,7 @@ static int dag_read(pcap_t *p, int cnt, unsigned short packet_len = 0; int caplen = 0; - struct pcap_pkthdr pcap_header; + struct pcap_pkthdr *pcap_header; 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; @@ -320,24 +320,28 @@ static int dag_read(pcap_t *p, int cnt, ts = header->ts; } - pcap_header.ts.tv_sec = ts >> 32; + pcap_header = pcap_header_new(p); + if ( ! pcap_header ) + return -1; + + pcap_header->ts.tv_sec = ts >> 32; 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++; + 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++; } /* Fill in our own header data */ - pcap_header.caplen = caplen; - pcap_header.len = packet_len; + 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); + callback(user, pcap_header, dp); /* Only count packets that pass the filter, for consistency with standard Linux behaviour. */ processed++; diff -urp libpcap-0.8.1.orig/pcap-dlpi.c libpcap-0.8.1/pcap-dlpi.c --- libpcap-0.8.1.orig/pcap-dlpi.c 2003-11-21 10:20:46.000000000 +0000 +++ libpcap-0.8.1/pcap-dlpi.c 2004-01-05 21:48:52.000000000 +0000 @@ -198,7 +198,7 @@ pcap_read_dlpi(pcap_t *p, int cnt, pcap_ #endif int flags; struct strbuf data; - struct pcap_pkthdr pkthdr; + struct pcap_pkthdr *pkthdr; flags = 0; cc = p->cc; @@ -281,18 +281,23 @@ pcap_read_dlpi(pcap_t *p, int cnt, pcap_ #endif ++p->md.stat.ps_recv; if (bpf_filter(fcode, pk, origlen, caplen)) { + + pkthdr = pcap_header_new(p); + if ( ! pkthdr ) + return -1; + #ifdef HAVE_SYS_BUFMOD_H - pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec; - pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec; + pkthdr->ts.tv_sec = sbp->sbh_timestamp.tv_sec; + pkthdr->ts.tv_usec = sbp->sbh_timestamp.tv_usec; #else (void)gettimeofday(&pkthdr.ts, NULL); #endif - pkthdr.len = origlen; - pkthdr.caplen = caplen; + pkthdr->len = origlen; + pkthdr->caplen = caplen; /* Insure caplen does not exceed snapshot */ - if (pkthdr.caplen > p->snapshot) - pkthdr.caplen = p->snapshot; - (*callback)(user, &pkthdr, pk); + if (pkthdr->caplen > p->snapshot) + pkthdr->caplen = p->snapshot; + (*callback)(user, pkthdr, pk); if (++n >= cnt && cnt >= 0) { p->cc = ep - bp; p->bp = bp; diff -urp libpcap-0.8.1.orig/pcap-int.h libpcap-0.8.1/pcap-int.h --- libpcap-0.8.1.orig/pcap-int.h 2003-12-15 01:42:24.000000000 +0000 +++ libpcap-0.8.1/pcap-int.h 2004-01-06 01:10:27.240856176 +0000 @@ -160,6 +160,22 @@ struct pcap_timeval { bpf_int32 tv_usec; /* microseconds */ }; + +struct buffer_head { + int refcount; + unsigned char buf; +}; + + +struct pcap_ref_pkthdr { + struct timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ + struct buffer_head *bhead; +}; + + + /* * How a `pcap_pkthdr' is actually stored in the dumpfile. * @@ -218,6 +234,11 @@ int yylex(void); #endif /* XXX should these be in pcap.h? */ + +int pcap_buffer_lock(pcap_t *p); +void pcap_buffer_release(pcap_t *p); +struct pcap_pkthdr *pcap_header_new(pcap_t *p); + int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *); int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *); diff -urp libpcap-0.8.1.orig/pcap-linux.c libpcap-0.8.1/pcap-linux.c --- libpcap-0.8.1.orig/pcap-linux.c 2003-11-21 10:20:46.000000000 +0000 +++ libpcap-0.8.1/pcap-linux.c 2004-01-05 23:11:39.000000000 +0000 @@ -447,7 +447,7 @@ pcap_read_packet(pcap_t *handle, pcap_ha #endif socklen_t fromlen; int packet_len, caplen; - struct pcap_pkthdr pcap_header; + struct pcap_pkthdr *pcap_header; #ifdef HAVE_PF_PACKET_SOCKETS /* @@ -623,13 +623,17 @@ pcap_read_packet(pcap_t *handle, pcap_ha /* Fill in our own header data */ - if (ioctl(handle->fd, SIOCGSTAMP, &pcap_header.ts) == -1) { + pcap_header = pcap_header_new(handle); + if ( ! pcap_header ) + return -1; + + if (ioctl(handle->fd, SIOCGSTAMP, &pcap_header->ts) == -1) { snprintf(handle->errbuf, sizeof(handle->errbuf), "ioctl: %s", pcap_strerror(errno)); return -1; } - pcap_header.caplen = caplen; - pcap_header.len = packet_len; + pcap_header->caplen = caplen; + pcap_header->len = packet_len; /* * Count the packet. @@ -667,7 +671,7 @@ pcap_read_packet(pcap_t *handle, pcap_ha handle->md.stat.ps_recv++; /* Call the user supplied callback function */ - callback(userdata, &pcap_header, bp); + callback(userdata, pcap_header, bp); return 1; } diff -urp libpcap-0.8.1.orig/pcap-nit.c libpcap-0.8.1/pcap-nit.c --- libpcap-0.8.1.orig/pcap-nit.c 2003-11-21 10:20:47.000000000 +0000 +++ libpcap-0.8.1/pcap-nit.c 2004-01-06 00:40:51.495810456 +0000 @@ -176,11 +176,17 @@ pcap_read_nit(pcap_t *p, int cnt, pcap_h if (caplen > p->snapshot) caplen = p->snapshot; if (bpf_filter(fcode, cp, nh->nh_wirelen, caplen)) { - struct pcap_pkthdr h; - h.ts = nh->nh_timestamp; - h.len = nh->nh_wirelen; - h.caplen = caplen; - (*callback)(user, &h, cp); + struct pcap_pkthdr *h; + + h = pcap_header_new(p); + if ( ! h ) + return -1; + + h->ts = nh->nh_timestamp; + h->len = nh->nh_wirelen; + h->caplen = caplen; + + (*callback)(user, h, cp); if (++n >= cnt && cnt >= 0) { p->cc = ep - bp; p->bp = bp; diff -urp libpcap-0.8.1.orig/pcap-pf.c libpcap-0.8.1/pcap-pf.c --- libpcap-0.8.1.orig/pcap-pf.c 2003-11-22 00:32:55.000000000 +0000 +++ libpcap-0.8.1/pcap-pf.c 2004-01-06 00:42:02.024088528 +0000 @@ -198,16 +198,23 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_h */ if (fcode == NULL || bpf_filter(fcode, p, sp->ens_count, buflen)) { - struct pcap_pkthdr h; + struct pcap_pkthdr *h; + pc->md.TotAccepted++; - h.ts = sp->ens_tstamp; + + h = pcap_header_new(pc); + if ( ! h ) + return -1; + + h->ts = sp->ens_tstamp; #ifdef PCAP_FDDIPAD - h.len = sp->ens_count - pad; + h->len = sp->ens_count - pad; #else - h.len = sp->ens_count; + h->len = sp->ens_count; #endif - h.caplen = buflen; - (*callback)(user, &h, p); + h->caplen = buflen; + + (*callback)(user, h, p); if (++n >= cnt && cnt > 0) { pc->cc = cc; pc->bp = bp; diff -urp libpcap-0.8.1.orig/pcap-snit.c libpcap-0.8.1/pcap-snit.c --- libpcap-0.8.1.orig/pcap-snit.c 2003-11-21 10:20:48.000000000 +0000 +++ libpcap-0.8.1/pcap-snit.c 2004-01-06 00:38:26.353875384 +0000 @@ -188,11 +188,17 @@ pcap_read_snit(pcap_t *p, int cnt, pcap_ caplen = p->snapshot; if (bpf_filter(fcode, cp, nlp->nh_pktlen, caplen)) { - struct pcap_pkthdr h; - h.ts = ntp->nh_timestamp; - h.len = nlp->nh_pktlen; - h.caplen = caplen; - (*callback)(user, &h, cp); + struct pcap_pkthdr *h; + + h = pcap_header_new(p); + if ( ! h ) + return -1; + + h->ts = ntp->nh_timestamp; + h->len = nlp->nh_pktlen; + h->caplen = caplen; + + (*callback)(user, h, cp); if (++n >= cnt && cnt >= 0) { p->cc = ep - bp; p->bp = bp; diff -urp libpcap-0.8.1.orig/pcap-snoop.c libpcap-0.8.1/pcap-snoop.c --- libpcap-0.8.1.orig/pcap-snoop.c 2003-11-21 10:20:48.000000000 +0000 +++ libpcap-0.8.1/pcap-snoop.c 2004-01-06 00:41:02.626118392 +0000 @@ -113,13 +113,20 @@ again: if (p->fcode.bf_insns == NULL || bpf_filter(p->fcode.bf_insns, cp, datalen, caplen)) { - struct pcap_pkthdr h; + struct pcap_pkthdr *h; + ++p->md.stat.ps_recv; - h.ts.tv_sec = sh->snoop_timestamp.tv_sec; - h.ts.tv_usec = sh->snoop_timestamp.tv_usec; - h.len = datalen; - h.caplen = caplen; - (*callback)(user, &h, cp); + + h = pcap_header_new(p); + if ( ! h ) + return -1; + + h->len = datalen; + h->caplen = caplen; + h->ts.tv_sec = sh->snoop_timestamp.tv_sec; + h->ts.tv_usec = sh->snoop_timestamp.tv_usec; + + (*callback)(user, h, cp); return (1); } return (0); diff -urp libpcap-0.8.1.orig/pcap-win32.c libpcap-0.8.1/pcap-win32.c --- libpcap-0.8.1.orig/pcap-win32.c 2003-11-30 02:32:02.000000000 +0000 +++ libpcap-0.8.1/pcap-win32.c 2004-01-06 01:06:23.533905264 +0000 @@ -97,7 +97,8 @@ pcap_read_win32(pcap_t *p, int cnt, pcap int cc; int n = 0; register u_char *bp, *ep; - + struct pcap_pkthdr *pcap_header; + cc = p->cc; if (p->cc == 0) { /* @@ -162,7 +163,16 @@ pcap_read_win32(pcap_t *p, int cnt, pcap /* * XXX A bpf_hdr matches a pcap_pkthdr. */ - (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen); + pcap_header = pcap_header_new(p); + if ( ! pcap_header ) + return -1; + + pcap_header->ts.tv_sec = bhp->bh_tstamp.tv_sec; + pcap_header->ts.tv_usec = bhp->bh_tstamp.tv_usec; + pcap_header->caplen = caplen; + pcap_header->len = bhp->bh_datalen; + + (*callback)(user, pcap_header, bp + hdrlen); bp += BPF_WORDALIGN(caplen + hdrlen); if (++n >= cnt && cnt > 0) { p->bp = bp; diff -urp libpcap-0.8.1.orig/pcap.c libpcap-0.8.1/pcap.c --- libpcap-0.8.1.orig/pcap.c 2003-11-21 10:20:49.000000000 +0000 +++ libpcap-0.8.1/pcap.c 2004-01-06 01:10:20.657856944 +0000 @@ -66,11 +66,141 @@ static const char rcsid[] _U_ = #include #endif + +#define get_buffer_head(ptr, type, member) \ + ((type *) ((void *) (ptr) - (void *) (& ((type *) 0)->member))) + + +static void *(*alloc_buffer_cb)(size_t size) = NULL; +static void (*free_buffer_cb)(void *ptr) = NULL; + + + +int pcap_buffer_lock(pcap_t *p) +{ + struct buffer_head *bhead; + + if ( ! alloc_buffer_cb ) + return 0; + + bhead = alloc_buffer_cb(sizeof(struct buffer_head) + p->bufsize + p->offset); + if ( ! bhead ) { + snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); + return -1; + } + + bhead->refcount = 1; + + if ( p->buffer ) + free(p->buffer); + + p->buffer = &bhead->buf; + + return 0; +} + + + + +void pcap_buffer_release(pcap_t *p) +{ + struct buffer_head *bhead; + + if ( ! alloc_buffer_cb ) + return; + + bhead = get_buffer_head(p->buffer, struct buffer_head, buf); + if ( --bhead->refcount == 0 ) + free_buffer_cb(bhead); + + p->buffer = NULL; +} + + + + + +struct pcap_pkthdr *pcap_header_new(pcap_t *p) +{ + struct pcap_ref_pkthdr *ref; + + if ( ! alloc_buffer_cb ) { + static struct pcap_pkthdr hdr; + return &hdr; + } + + ref = malloc(sizeof(struct pcap_ref_pkthdr)); + if ( ! ref ) { + snprintf(p->errbuf, sizeof(p->errbuf), "malloc: %s", pcap_strerror(errno)); + return NULL; + } + + ref->bhead = get_buffer_head(p->buffer, struct buffer_head, buf); + ref->bhead->refcount++; + + return (struct pcap_pkthdr *) ref; +} + + + + +void pcap_header_free(const struct pcap_pkthdr *phdr) +{ + struct pcap_ref_pkthdr *ref; + + if ( ! alloc_buffer_cb ) + return; + + ref = (struct pcap_ref_pkthdr *) phdr; + if ( --ref->bhead->refcount == 0 ) + free_buffer_cb(ref->bhead); + + free(ref); +} + + + + +void pcap_header_reference(const struct pcap_pkthdr *phdr) +{ + struct pcap_ref_pkthdr *ref; + + if ( ! alloc_buffer_cb ) + return; + + ref = (struct pcap_ref_pkthdr *) phdr; + ref->bhead->refcount++; +} + + + + +void pcap_set_alloc_func(pcap_t *p, void *(*alloc)(size_t size), void (*free)(void *ptr)) +{ + alloc_buffer_cb = alloc; + free_buffer_cb = free; +} + + + + int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { + int ret; + + if ( p->cc == 0 ) { + ret = pcap_buffer_lock(p); + if ( ret < 0 ) + return -1; + } + + ret = p->read_op(p, cnt, callback, user); - return p->read_op(p, cnt, callback, user); + if ( p->cc == 0 ) + pcap_buffer_release(p); + + return ret; } /* @@ -79,14 +209,19 @@ pcap_dispatch(pcap_t *p, int cnt, pcap_h int pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { - - return p->read_op(p, cnt, callback, user); + return pcap_dispatch(p, cnt, callback, user); } int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user) { register int n; + + if ( p->cc == 0 ) { + n = pcap_buffer_lock(p); + if ( n < 0 ) + return -1; + } for (;;) { if (p->sf.rfile != NULL) { @@ -104,13 +239,21 @@ pcap_loop(pcap_t *p, int cnt, pcap_handl } while (n == 0); } if (n <= 0) - return (n); + break; + if (cnt > 0) { cnt -= n; - if (cnt <= 0) - return (0); + if (cnt <= 0) { + n = 0; + break; + } } } + + if ( p->cc == 0 ) + pcap_buffer_release(p); + + return n; } struct singleton { @@ -139,7 +282,7 @@ pcap_next(pcap_t *p, struct pcap_pkthdr } struct pkt_for_fakecallback { - struct pcap_pkthdr *hdr; + struct pcap_pkthdr **hdr; const u_char **pkt; }; @@ -149,7 +292,7 @@ pcap_fakecallback(u_char *userData, cons { struct pkt_for_fakecallback *sp = (struct pkt_for_fakecallback *)userData; - *sp->hdr = *h; + *sp->hdr = h; *sp->pkt = pkt; } @@ -158,13 +301,10 @@ pcap_next_ex(pcap_t *p, struct pcap_pkth const u_char **pkt_data) { struct pkt_for_fakecallback s; - - s.hdr = &p->pcap_header; + + s.hdr = pkt_header; s.pkt = pkt_data; - - /* Saves a pointer to the packet headers */ - *pkt_header= &p->pcap_header; - + if (p->sf.rfile != NULL) { int status; @@ -199,7 +339,7 @@ pcap_next_ex(pcap_t *p, struct pcap_pkth * The first one ('0') conflicts with the return code of 0 from * pcap_offline_read() meaning "end of file". */ - return (p->read_op(p, 1, pcap_fakecallback, (u_char *)&s)); + return pcap_dispatch(p, 1, pcap_fakecallback, (u_char *)&s); } /* diff -urp libpcap-0.8.1.orig/pcap.h libpcap-0.8.1/pcap.h --- libpcap-0.8.1.orig/pcap.h 2003-11-21 10:20:50.000000000 +0000 +++ libpcap-0.8.1/pcap.h 2004-01-05 21:34:59.000000000 +0000 @@ -167,6 +167,10 @@ struct pcap_addr { typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, const u_char *); + void pcap_header_free(const struct pcap_pkthdr *phdr); + void pcap_set_alloc_func(pcap_t *p, void *(*alloc)(size_t size), void (*free)(void *ptr)); + void pcap_header_reference(const struct pcap_pkthdr *phdr); + char *pcap_lookupdev(char *); int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); pcap_t *pcap_open_live(const char *, int, int, int, char *);