xref: /netbsd-src/external/bsd/libpcap/dist/pcap-enet.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
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