1 /* $NetBSD: pcap-enet.c,v 1.1.1.3 2013/04/06 15:57:49 christos Exp $ */ 2 3 /* 4 * Stanford Enetfilter subroutines for tcpdump 5 * 6 * Based on the MERIT NNstat etherifrt.c and the Ultrix pcap-pf.c 7 * subroutines. 8 * 9 * Rayan Zachariassen, CA*Net 10 */ 11 #ifndef lint 12 static const char rcsid[] _U_ = 13 "@(#) Header: /tcpdump/master/libpcap/pcap-enet.c,v 1.9 2006-10-04 18:09:22 guy Exp "; 14 #endif 15 16 #ifdef HAVE_CONFIG_H 17 #include "config.h" 18 #endif 19 20 #include <sys/types.h> 21 #include <sys/time.h> 22 #include <sys/file.h> 23 #include <sys/ioctl.h> 24 #include <sys/socket.h> 25 26 #include <net/if.h> 27 #include <pcap/bpf.h> 28 #include <net/enet.h> 29 30 #include <netinet/in.h> 31 #include <netinet/if_ether.h> 32 33 #include <stdio.h> 34 #include <errno.h> 35 36 #include "interface.h" 37 38 struct packet_header { 39 #ifdef IBMRTPC 40 struct LengthWords length; 41 struct tap_header tap; 42 #endif /* IBMRTPC */ 43 u_char packet[8] 44 }; 45 46 extern int errno; 47 48 #define BUFSPACE (4*1024) 49 50 /* Forwards */ 51 static void efReadError(int, char *); 52 53 void 54 readloop(int cnt, int if_fd, struct bpf_program *fp, printfunc printit) 55 { 56 #ifdef IBMRTPC 57 register struct packet_header *ph; 58 register u_char *bp; 59 register int inc; 60 #else /* !IBMRTPC */ 61 static struct timeval tv = { 0 }; 62 #endif /* IBMRTPC */ 63 register int cc, caplen; 64 register struct bpf_insn *fcode = fp->bf_insns; 65 union { 66 struct packet_header hdr; 67 u_char p[BUFSPACE]; 68 u_short s; 69 } buf; 70 71 while (1) { 72 if ((cc = read(if_fd, (char *)buf.p, sizeof(buf))) < 0) 73 efReadError(if_fd, "reader"); 74 75 #ifdef IBMRTPC 76 /* 77 * Loop through each packet. 78 */ 79 bp = buf.p; 80 while (cc > 0) { 81 ph = (struct packet_header *)bp; 82 caplen = ph->tap.th_wirelen > snaplen ? snaplen : ph->tap 83 .th_wirelen ; 84 if (bpf_filter(fcode, (char *)ph->packet, 85 ph->tap.th_wirelen, caplen)) { 86 if (cnt >= 0 && --cnt < 0) 87 goto out; 88 (*printit)((char *)ph->packet, 89 (struct timeval *)ph->tap.th_timestamp, 90 ph->tap.th_wirelen, caplen); 91 } 92 inc = ph->length.PacketOffset; 93 cc -= inc; 94 bp += inc; 95 } 96 #else /* !IBMRTPC */ 97 caplen = cc > snaplen ? snaplen : cc ; 98 if (bpf_filter(fcode, buf.hdr.packet, cc, caplen)) { 99 if (cnt >= 0 && --cnt < 0) 100 goto out; 101 (*printit)(buf.hdr.packet, &tv, cc, caplen); 102 } 103 #endif /* IBMRTPC */ 104 } 105 out: 106 wrapup(if_fd); 107 } 108 109 /* Call ONLY if read() has returned an error on packet filter */ 110 static void 111 efReadError(int fid, char *msg) 112 { 113 if (errno == EINVAL) { /* read MAXINT bytes already! */ 114 if (lseek(fid, 0, 0) < 0) { 115 perror("tcpdump: efReadError/lseek"); 116 exit(-1); 117 } 118 else 119 return; 120 } 121 else { 122 (void) fprintf(stderr, "tcpdump: "); 123 perror(msg); 124 exit(-1); 125 } 126 } 127 128 void 129 wrapup(int fd) 130 { 131 #ifdef IBMRTPC 132 struct enstats es; 133 134 if (ioctl(fd, EIOSTATS, &es) == -1) { 135 perror("tcpdump: enet ioctl EIOSTATS error"); 136 exit(-1); 137 } 138 139 fprintf(stderr, "%d packets queued", es.enStat_Rcnt); 140 if (es.enStat_Rdrops > 0) 141 fprintf(stderr, ", %d dropped", es.enStat_Rdrops); 142 if (es.enStat_Reads > 0) 143 fprintf(stderr, ", %d tcpdump %s", es.enStat_Reads, 144 es.enStat_Reads > 1 ? "reads" : "read"); 145 if (es.enStat_MaxRead > 1) 146 fprintf(stderr, ", %d packets in largest read", 147 es.enStat_MaxRead); 148 putc('\n', stderr); 149 #endif /* IBMRTPC */ 150 close(fd); 151 } 152 153 int 154 initdevice(char *device, int pflag, int *linktype) 155 { 156 struct eniocb ctl; 157 struct enfilter filter; 158 u_int maxwaiting; 159 int if_fd; 160 161 #ifdef IBMRTPC 162 GETENETDEVICE(0, O_RDONLY, &if_fd); 163 #else /* !IBMRTPC */ 164 if_fd = open("/dev/enet", O_RDONLY, 0); 165 #endif /* IBMRTPC */ 166 167 if (if_fd == -1) { 168 perror("tcpdump: enet open error"); 169 error( 170 "your system may not be properly configured; see \"man enet(4)\""); 171 exit(-1); 172 } 173 174 /* Get operating parameters. */ 175 176 if (ioctl(if_fd, EIOCGETP, (char *)&ctl) == -1) { 177 perror("tcpdump: enet ioctl EIOCGETP error"); 178 exit(-1); 179 } 180 181 /* Set operating parameters. */ 182 183 #ifdef IBMRTPC 184 ctl.en_rtout = 1 * ctl.en_hz; 185 ctl.en_tr_etherhead = 1; 186 ctl.en_tap_network = 1; 187 ctl.en_multi_packet = 1; 188 ctl.en_maxlen = BUFSPACE; 189 #else /* !IBMRTPC */ 190 ctl.en_rtout = 64; /* randomly picked value for HZ */ 191 #endif /* IBMRTPC */ 192 if (ioctl(if_fd, EIOCSETP, &ctl) == -1) { 193 perror("tcpdump: enet ioctl EIOCSETP error"); 194 exit(-1); 195 } 196 197 /* Flush the receive queue, since we've changed 198 the operating parameters and we otherwise might 199 receive data without headers. */ 200 201 if (ioctl(if_fd, EIOCFLUSH) == -1) { 202 perror("tcpdump: enet ioctl EIOCFLUSH error"); 203 exit(-1); 204 } 205 206 /* Set the receive queue depth to its maximum. */ 207 208 maxwaiting = ctl.en_maxwaiting; 209 if (ioctl(if_fd, EIOCSETW, &maxwaiting) == -1) { 210 perror("tcpdump: enet ioctl EIOCSETW error"); 211 exit(-1); 212 } 213 214 #ifdef IBMRTPC 215 /* Clear statistics. */ 216 217 if (ioctl(if_fd, EIOCLRSTAT, 0) == -1) { 218 perror("tcpdump: enet ioctl EIOCLRSTAT error"); 219 exit(-1); 220 } 221 #endif /* IBMRTPC */ 222 223 /* Set the filter (accept all packets). */ 224 225 filter.enf_Priority = 3; 226 filter.enf_FilterLen = 0; 227 if (ioctl(if_fd, EIOCSETF, &filter) == -1) { 228 perror("tcpdump: enet ioctl EIOCSETF error"); 229 exit(-1); 230 } 231 /* 232 * "enetfilter" supports only ethernets. 233 */ 234 *linktype = DLT_EN10MB; 235 236 return(if_fd); 237 } 238