117683Spst/* 217683Spst * Stanford Enetfilter subroutines for tcpdump 317683Spst * 417683Spst * Based on the MERIT NNstat etherifrt.c and the Ultrix pcap-pf.c 517683Spst * subroutines. 617683Spst * 717683Spst * Rayan Zachariassen, CA*Net 817683Spst */ 975107Sfenner#ifndef lint 10127664Sbmsstatic const char rcsid[] _U_ = 11214518Srpaulo "@(#) $Header: /tcpdump/master/libpcap/pcap-enet.c,v 1.9 2006-10-04 18:09:22 guy Exp $"; 1275107Sfenner#endif 1317683Spst 1475107Sfenner#ifdef HAVE_CONFIG_H 1575107Sfenner#include "config.h" 1675107Sfenner#endif 1775107Sfenner 1817683Spst#include <sys/types.h> 1917683Spst#include <sys/time.h> 2017683Spst#include <sys/file.h> 2117683Spst#include <sys/ioctl.h> 2217683Spst#include <sys/socket.h> 2317683Spst 2417683Spst#include <net/if.h> 25190225Srpaulo#include <pcap/bpf.h> 2617683Spst#include <net/enet.h> 2717683Spst 2817683Spst#include <netinet/in.h> 2917683Spst#include <netinet/if_ether.h> 3017683Spst 3117683Spst#include <stdio.h> 3217683Spst#include <errno.h> 3317683Spst 3417683Spst#include "interface.h" 3517683Spst 3617683Spststruct packet_header { 3717683Spst#ifdef IBMRTPC 3817683Spst struct LengthWords length; 3917683Spst struct tap_header tap; 4017683Spst#endif /* IBMRTPC */ 4117683Spst u_char packet[8] 4217683Spst}; 4317683Spst 4417683Spstextern int errno; 4517683Spst 4617683Spst#define BUFSPACE (4*1024) 4717683Spst 4817683Spst/* Forwards */ 4917683Spststatic void efReadError(int, char *); 5017683Spst 5117683Spstvoid 5217683Spstreadloop(int cnt, int if_fd, struct bpf_program *fp, printfunc printit) 5317683Spst{ 5417683Spst#ifdef IBMRTPC 5517683Spst register struct packet_header *ph; 5617683Spst register u_char *bp; 5717683Spst register int inc; 5817683Spst#else /* !IBMRTPC */ 5917683Spst static struct timeval tv = { 0 }; 6017683Spst#endif /* IBMRTPC */ 6117683Spst register int cc, caplen; 6217683Spst register struct bpf_insn *fcode = fp->bf_insns; 6317683Spst union { 6417683Spst struct packet_header hdr; 6517683Spst u_char p[BUFSPACE]; 6617683Spst u_short s; 6717683Spst } buf; 6817683Spst 6917683Spst while (1) { 7017683Spst if ((cc = read(if_fd, (char *)buf.p, sizeof(buf))) < 0) 7117683Spst efReadError(if_fd, "reader"); 7217683Spst 7317683Spst#ifdef IBMRTPC 7417683Spst /* 7517683Spst * Loop through each packet. 7617683Spst */ 7717683Spst bp = buf.p; 7817683Spst while (cc > 0) { 7917683Spst ph = (struct packet_header *)bp; 8017683Spst caplen = ph->tap.th_wirelen > snaplen ? snaplen : ph->tap 8117683Spst.th_wirelen ; 8217683Spst if (bpf_filter(fcode, (char *)ph->packet, 8317683Spst ph->tap.th_wirelen, caplen)) { 8417683Spst if (cnt >= 0 && --cnt < 0) 8517683Spst goto out; 8617683Spst (*printit)((char *)ph->packet, 8717683Spst (struct timeval *)ph->tap.th_timestamp, 8817683Spst ph->tap.th_wirelen, caplen); 8917683Spst } 9017683Spst inc = ph->length.PacketOffset; 9117683Spst cc -= inc; 9217683Spst bp += inc; 9317683Spst } 9417683Spst#else /* !IBMRTPC */ 9517683Spst caplen = cc > snaplen ? snaplen : cc ; 9617683Spst if (bpf_filter(fcode, buf.hdr.packet, cc, caplen)) { 9717683Spst if (cnt >= 0 && --cnt < 0) 9817683Spst goto out; 9917683Spst (*printit)(buf.hdr.packet, &tv, cc, caplen); 10017683Spst } 10117683Spst#endif /* IBMRTPC */ 10217683Spst } 10317683Spst out: 10417683Spst wrapup(if_fd); 10517683Spst} 10617683Spst 10717683Spst/* Call ONLY if read() has returned an error on packet filter */ 10817683Spststatic void 10917683SpstefReadError(int fid, char *msg) 11017683Spst{ 11117683Spst if (errno == EINVAL) { /* read MAXINT bytes already! */ 11217683Spst if (lseek(fid, 0, 0) < 0) { 11317683Spst perror("tcpdump: efReadError/lseek"); 11417683Spst exit(-1); 11517683Spst } 11617683Spst else 11717683Spst return; 11817683Spst } 11917683Spst else { 12017683Spst (void) fprintf(stderr, "tcpdump: "); 12117683Spst perror(msg); 12217683Spst exit(-1); 12317683Spst } 12417683Spst} 12517683Spst 12617683Spstvoid 12717683Spstwrapup(int fd) 12817683Spst{ 12917683Spst#ifdef IBMRTPC 13017683Spst struct enstats es; 13117683Spst 13217683Spst if (ioctl(fd, EIOSTATS, &es) == -1) { 13317683Spst perror("tcpdump: enet ioctl EIOSTATS error"); 13417683Spst exit(-1); 13517683Spst } 136127664Sbms 13717683Spst fprintf(stderr, "%d packets queued", es.enStat_Rcnt); 13817683Spst if (es.enStat_Rdrops > 0) 13917683Spst fprintf(stderr, ", %d dropped", es.enStat_Rdrops); 14017683Spst if (es.enStat_Reads > 0) 14117683Spst fprintf(stderr, ", %d tcpdump %s", es.enStat_Reads, 14217683Spst es.enStat_Reads > 1 ? "reads" : "read"); 14317683Spst if (es.enStat_MaxRead > 1) 144127664Sbms fprintf(stderr, ", %d packets in largest read", 14517683Spst es.enStat_MaxRead); 14617683Spst putc('\n', stderr); 14717683Spst#endif /* IBMRTPC */ 14817683Spst close(fd); 14917683Spst} 15017683Spst 15117683Spstint 15217683Spstinitdevice(char *device, int pflag, int *linktype) 15317683Spst{ 15417683Spst struct eniocb ctl; 15517683Spst struct enfilter filter; 15617683Spst u_int maxwaiting; 15717683Spst int if_fd; 15817683Spst 15917683Spst#ifdef IBMRTPC 16017683Spst GETENETDEVICE(0, O_RDONLY, &if_fd); 16117683Spst#else /* !IBMRTPC */ 16217683Spst if_fd = open("/dev/enet", O_RDONLY, 0); 16317683Spst#endif /* IBMRTPC */ 16417683Spst 16517683Spst if (if_fd == -1) { 16617683Spst perror("tcpdump: enet open error"); 16717683Spst error( 16817683Spst"your system may not be properly configured; see \"man enet(4)\""); 16917683Spst exit(-1); 17017683Spst } 17117683Spst 17217683Spst /* Get operating parameters. */ 17317683Spst 17417683Spst if (ioctl(if_fd, EIOCGETP, (char *)&ctl) == -1) { 17517683Spst perror("tcpdump: enet ioctl EIOCGETP error"); 17617683Spst exit(-1); 17717683Spst } 17817683Spst 17917683Spst /* Set operating parameters. */ 18017683Spst 18117683Spst#ifdef IBMRTPC 18217683Spst ctl.en_rtout = 1 * ctl.en_hz; 18317683Spst ctl.en_tr_etherhead = 1; 18417683Spst ctl.en_tap_network = 1; 18517683Spst ctl.en_multi_packet = 1; 18617683Spst ctl.en_maxlen = BUFSPACE; 18717683Spst#else /* !IBMRTPC */ 18817683Spst ctl.en_rtout = 64; /* randomly picked value for HZ */ 18917683Spst#endif /* IBMRTPC */ 19017683Spst if (ioctl(if_fd, EIOCSETP, &ctl) == -1) { 19117683Spst perror("tcpdump: enet ioctl EIOCSETP error"); 19217683Spst exit(-1); 19317683Spst } 19417683Spst 19517683Spst /* Flush the receive queue, since we've changed 19617683Spst the operating parameters and we otherwise might 19717683Spst receive data without headers. */ 19817683Spst 19917683Spst if (ioctl(if_fd, EIOCFLUSH) == -1) { 20017683Spst perror("tcpdump: enet ioctl EIOCFLUSH error"); 20117683Spst exit(-1); 20217683Spst } 20317683Spst 20417683Spst /* Set the receive queue depth to its maximum. */ 20517683Spst 20617683Spst maxwaiting = ctl.en_maxwaiting; 20717683Spst if (ioctl(if_fd, EIOCSETW, &maxwaiting) == -1) { 20817683Spst perror("tcpdump: enet ioctl EIOCSETW error"); 20917683Spst exit(-1); 21017683Spst } 21117683Spst 21217683Spst#ifdef IBMRTPC 21317683Spst /* Clear statistics. */ 21417683Spst 21517683Spst if (ioctl(if_fd, EIOCLRSTAT, 0) == -1) { 21617683Spst perror("tcpdump: enet ioctl EIOCLRSTAT error"); 21717683Spst exit(-1); 21817683Spst } 21917683Spst#endif /* IBMRTPC */ 22017683Spst 22117683Spst /* Set the filter (accept all packets). */ 22217683Spst 22317683Spst filter.enf_Priority = 3; 22417683Spst filter.enf_FilterLen = 0; 22517683Spst if (ioctl(if_fd, EIOCSETF, &filter) == -1) { 22617683Spst perror("tcpdump: enet ioctl EIOCSETF error"); 22717683Spst exit(-1); 22817683Spst } 22917683Spst /* 23017683Spst * "enetfilter" supports only ethernets. 23117683Spst */ 23217683Spst *linktype = DLT_EN10MB; 23317683Spst 23417683Spst return(if_fd); 23517683Spst} 236