1335640Shselasky/* 2335640Shselasky * Stanford Enetfilter subroutines for tcpdump 3335640Shselasky * 4335640Shselasky * Based on the MERIT NNstat etherifrt.c and the Ultrix pcap-pf.c 5335640Shselasky * subroutines. 6335640Shselasky * 7335640Shselasky * Rayan Zachariassen, CA*Net 8335640Shselasky */ 9335640Shselasky 10335640Shselasky#ifdef HAVE_CONFIG_H 11335640Shselasky#include <config.h> 12335640Shselasky#endif 13335640Shselasky 14335640Shselasky#include <sys/types.h> 15335640Shselasky#include <sys/time.h> 16335640Shselasky#include <sys/file.h> 17335640Shselasky#include <sys/ioctl.h> 18335640Shselasky#include <sys/socket.h> 19335640Shselasky 20335640Shselasky#include <net/if.h> 21335640Shselasky#include <pcap/bpf.h> 22335640Shselasky#include <net/enet.h> 23335640Shselasky 24335640Shselasky#include <netinet/in.h> 25335640Shselasky#include <netinet/if_ether.h> 26335640Shselasky 27335640Shselasky#include <stdio.h> 28335640Shselasky#include <errno.h> 29335640Shselasky 30335640Shselasky#include "interface.h" 31335640Shselasky 32335640Shselaskystruct packet_header { 33335640Shselasky#ifdef IBMRTPC 34335640Shselasky struct LengthWords length; 35335640Shselasky struct tap_header tap; 36335640Shselasky#endif /* IBMRTPC */ 37335640Shselasky u_char packet[8] 38335640Shselasky}; 39335640Shselasky 40335640Shselaskyextern int errno; 41335640Shselasky 42335640Shselasky#define BUFSPACE (4*1024) 43335640Shselasky 44335640Shselasky/* Forwards */ 45335640Shselaskystatic void efReadError(int, char *); 46335640Shselasky 47335640Shselaskyvoid 48335640Shselaskyreadloop(int cnt, int if_fd, struct bpf_program *fp, printfunc printit) 49335640Shselasky{ 50335640Shselasky#ifdef IBMRTPC 51335640Shselasky register struct packet_header *ph; 52335640Shselasky register u_char *bp; 53335640Shselasky register int inc; 54335640Shselasky#else /* !IBMRTPC */ 55335640Shselasky static struct timeval tv = { 0 }; 56335640Shselasky#endif /* IBMRTPC */ 57335640Shselasky register int cc, caplen; 58335640Shselasky register struct bpf_insn *fcode = fp->bf_insns; 59335640Shselasky union { 60335640Shselasky struct packet_header hdr; 61335640Shselasky u_char p[BUFSPACE]; 62335640Shselasky u_short s; 63335640Shselasky } buf; 64335640Shselasky 65335640Shselasky while (1) { 66335640Shselasky if ((cc = read(if_fd, (char *)buf.p, sizeof(buf))) < 0) 67335640Shselasky efReadError(if_fd, "reader"); 68335640Shselasky 69335640Shselasky#ifdef IBMRTPC 70335640Shselasky /* 71335640Shselasky * Loop through each packet. 72335640Shselasky */ 73335640Shselasky bp = buf.p; 74335640Shselasky while (cc > 0) { 75335640Shselasky ph = (struct packet_header *)bp; 76335640Shselasky caplen = ph->tap.th_wirelen > snaplen ? snaplen : ph->tap 77335640Shselasky.th_wirelen ; 78335640Shselasky if (bpf_filter(fcode, (char *)ph->packet, 79335640Shselasky ph->tap.th_wirelen, caplen)) { 80335640Shselasky if (cnt >= 0 && --cnt < 0) 81335640Shselasky goto out; 82335640Shselasky (*printit)((char *)ph->packet, 83335640Shselasky (struct timeval *)ph->tap.th_timestamp, 84335640Shselasky ph->tap.th_wirelen, caplen); 85335640Shselasky } 86335640Shselasky inc = ph->length.PacketOffset; 87335640Shselasky cc -= inc; 88335640Shselasky bp += inc; 89335640Shselasky } 90335640Shselasky#else /* !IBMRTPC */ 91335640Shselasky caplen = cc > snaplen ? snaplen : cc ; 92335640Shselasky if (bpf_filter(fcode, buf.hdr.packet, cc, caplen)) { 93335640Shselasky if (cnt >= 0 && --cnt < 0) 94335640Shselasky goto out; 95335640Shselasky (*printit)(buf.hdr.packet, &tv, cc, caplen); 96335640Shselasky } 97335640Shselasky#endif /* IBMRTPC */ 98335640Shselasky } 99335640Shselasky out: 100335640Shselasky wrapup(if_fd); 101335640Shselasky} 102335640Shselasky 103335640Shselasky/* Call ONLY if read() has returned an error on packet filter */ 104335640Shselaskystatic void 105335640ShselaskyefReadError(int fid, char *msg) 106335640Shselasky{ 107335640Shselasky if (errno == EINVAL) { /* read MAXINT bytes already! */ 108335640Shselasky if (lseek(fid, 0, 0) < 0) { 109335640Shselasky perror("tcpdump: efReadError/lseek"); 110335640Shselasky exit(-1); 111335640Shselasky } 112335640Shselasky else 113335640Shselasky return; 114335640Shselasky } 115335640Shselasky else { 116335640Shselasky (void) fprintf(stderr, "tcpdump: "); 117335640Shselasky perror(msg); 118335640Shselasky exit(-1); 119335640Shselasky } 120335640Shselasky} 121335640Shselasky 122335640Shselaskyvoid 123335640Shselaskywrapup(int fd) 124335640Shselasky{ 125335640Shselasky#ifdef IBMRTPC 126335640Shselasky struct enstats es; 127335640Shselasky 128335640Shselasky if (ioctl(fd, EIOSTATS, &es) == -1) { 129335640Shselasky perror("tcpdump: enet ioctl EIOSTATS error"); 130335640Shselasky exit(-1); 131335640Shselasky } 132335640Shselasky 133335640Shselasky fprintf(stderr, "%d packets queued", es.enStat_Rcnt); 134335640Shselasky if (es.enStat_Rdrops > 0) 135335640Shselasky fprintf(stderr, ", %d dropped", es.enStat_Rdrops); 136335640Shselasky if (es.enStat_Reads > 0) 137335640Shselasky fprintf(stderr, ", %d tcpdump %s", es.enStat_Reads, 138335640Shselasky es.enStat_Reads > 1 ? "reads" : "read"); 139335640Shselasky if (es.enStat_MaxRead > 1) 140335640Shselasky fprintf(stderr, ", %d packets in largest read", 141335640Shselasky es.enStat_MaxRead); 142335640Shselasky putc('\n', stderr); 143335640Shselasky#endif /* IBMRTPC */ 144335640Shselasky close(fd); 145335640Shselasky} 146335640Shselasky 147335640Shselaskyint 148335640Shselaskyinitdevice(char *device, int pflag, int *linktype) 149335640Shselasky{ 150335640Shselasky struct eniocb ctl; 151335640Shselasky struct enfilter filter; 152335640Shselasky u_int maxwaiting; 153335640Shselasky int if_fd; 154335640Shselasky 155335640Shselasky#ifdef IBMRTPC 156335640Shselasky GETENETDEVICE(0, O_RDONLY, &if_fd); 157335640Shselasky#else /* !IBMRTPC */ 158335640Shselasky if_fd = open("/dev/enet", O_RDONLY, 0); 159335640Shselasky#endif /* IBMRTPC */ 160335640Shselasky 161335640Shselasky if (if_fd == -1) { 162335640Shselasky perror("tcpdump: enet open error"); 163335640Shselasky error( 164335640Shselasky"your system may not be properly configured; see \"man enet(4)\""); 165335640Shselasky exit(-1); 166335640Shselasky } 167335640Shselasky 168335640Shselasky /* Get operating parameters. */ 169335640Shselasky 170335640Shselasky if (ioctl(if_fd, EIOCGETP, (char *)&ctl) == -1) { 171335640Shselasky perror("tcpdump: enet ioctl EIOCGETP error"); 172335640Shselasky exit(-1); 173335640Shselasky } 174335640Shselasky 175335640Shselasky /* Set operating parameters. */ 176335640Shselasky 177335640Shselasky#ifdef IBMRTPC 178335640Shselasky ctl.en_rtout = 1 * ctl.en_hz; 179335640Shselasky ctl.en_tr_etherhead = 1; 180335640Shselasky ctl.en_tap_network = 1; 181335640Shselasky ctl.en_multi_packet = 1; 182335640Shselasky ctl.en_maxlen = BUFSPACE; 183335640Shselasky#else /* !IBMRTPC */ 184335640Shselasky ctl.en_rtout = 64; /* randomly picked value for HZ */ 185335640Shselasky#endif /* IBMRTPC */ 186335640Shselasky if (ioctl(if_fd, EIOCSETP, &ctl) == -1) { 187335640Shselasky perror("tcpdump: enet ioctl EIOCSETP error"); 188335640Shselasky exit(-1); 189335640Shselasky } 190335640Shselasky 191335640Shselasky /* Flush the receive queue, since we've changed 192335640Shselasky the operating parameters and we otherwise might 193335640Shselasky receive data without headers. */ 194335640Shselasky 195335640Shselasky if (ioctl(if_fd, EIOCFLUSH) == -1) { 196335640Shselasky perror("tcpdump: enet ioctl EIOCFLUSH error"); 197335640Shselasky exit(-1); 198335640Shselasky } 199335640Shselasky 200335640Shselasky /* Set the receive queue depth to its maximum. */ 201335640Shselasky 202335640Shselasky maxwaiting = ctl.en_maxwaiting; 203335640Shselasky if (ioctl(if_fd, EIOCSETW, &maxwaiting) == -1) { 204335640Shselasky perror("tcpdump: enet ioctl EIOCSETW error"); 205335640Shselasky exit(-1); 206335640Shselasky } 207335640Shselasky 208335640Shselasky#ifdef IBMRTPC 209335640Shselasky /* Clear statistics. */ 210335640Shselasky 211335640Shselasky if (ioctl(if_fd, EIOCLRSTAT, 0) == -1) { 212335640Shselasky perror("tcpdump: enet ioctl EIOCLRSTAT error"); 213335640Shselasky exit(-1); 214335640Shselasky } 215335640Shselasky#endif /* IBMRTPC */ 216335640Shselasky 217335640Shselasky /* Set the filter (accept all packets). */ 218335640Shselasky 219335640Shselasky filter.enf_Priority = 3; 220335640Shselasky filter.enf_FilterLen = 0; 221335640Shselasky if (ioctl(if_fd, EIOCSETF, &filter) == -1) { 222335640Shselasky perror("tcpdump: enet ioctl EIOCSETF error"); 223335640Shselasky exit(-1); 224335640Shselasky } 225335640Shselasky /* 226335640Shselasky * "enetfilter" supports only ethernets. 227335640Shselasky */ 228335640Shselasky *linktype = DLT_EN10MB; 229335640Shselasky 230335640Shselasky return(if_fd); 231335640Shselasky} 232