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