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