]> The Tcpdump Group git mirrors - libpcap/blob - pcap-bpf.c
8c11b51db118114f66caf6601efb13f67af0773e
[libpcap] / pcap-bpf.c
1 /*
2 * Copyright (c) 1993, 1994, 1995, 1996, 1998
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21 #ifndef lint
22 static const char rcsid[] =
23 "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.34 2000-07-10 04:50:05 assar Exp $ (LBL)";
24 #endif
25
26 #include <sys/param.h> /* optionally get BSD define */
27 #include <sys/time.h>
28 #include <sys/timeb.h>
29 #include <sys/socket.h>
30 #include <sys/file.h>
31 #include <sys/ioctl.h>
32
33 #include <net/if.h>
34
35 #include <ctype.h>
36 #include <errno.h>
37 #include <netdb.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #include "pcap-int.h"
44
45 #include "gnuc.h"
46 #ifdef HAVE_OS_PROTO_H
47 #include "os-proto.h"
48 #endif
49
50 #include "gencode.h"
51
52 int
53 pcap_stats(pcap_t *p, struct pcap_stat *ps)
54 {
55 struct bpf_stat s;
56
57 if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) {
58 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s",
59 pcap_strerror(errno));
60 return (-1);
61 }
62
63 ps->ps_recv = s.bs_recv;
64 ps->ps_drop = s.bs_drop;
65 return (0);
66 }
67
68 int
69 pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
70 {
71 int cc;
72 int n = 0;
73 register u_char *bp, *ep;
74
75 again:
76 cc = p->cc;
77 if (p->cc == 0) {
78 cc = read(p->fd, (char *)p->buffer, p->bufsize);
79 if (cc < 0) {
80 /* Don't choke when we get ptraced */
81 switch (errno) {
82
83 case EINTR:
84 goto again;
85
86 case EWOULDBLOCK:
87 return (0);
88 #if defined(sun) && !defined(BSD)
89 /*
90 * Due to a SunOS bug, after 2^31 bytes, the kernel
91 * file offset overflows and read fails with EINVAL.
92 * The lseek() to 0 will fix things.
93 */
94 case EINVAL:
95 if (lseek(p->fd, 0L, SEEK_CUR) +
96 p->bufsize < 0) {
97 (void)lseek(p->fd, 0L, SEEK_SET);
98 goto again;
99 }
100 /* fall through */
101 #endif
102 }
103 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read: %s",
104 pcap_strerror(errno));
105 return (-1);
106 }
107 bp = p->buffer;
108 } else
109 bp = p->bp;
110
111 /*
112 * Loop through each packet.
113 */
114 #define bhp ((struct bpf_hdr *)bp)
115 ep = bp + cc;
116 while (bp < ep) {
117 register int caplen, hdrlen;
118 caplen = bhp->bh_caplen;
119 hdrlen = bhp->bh_hdrlen;
120 /*
121 * XXX A bpf_hdr matches a pcap_pkthdr.
122 */
123 (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen);
124 bp += BPF_WORDALIGN(caplen + hdrlen);
125 if (++n >= cnt && cnt > 0) {
126 p->bp = bp;
127 p->cc = ep - bp;
128 return (n);
129 }
130 }
131 #undef bhp
132 p->cc = 0;
133 return (n);
134 }
135
136 static inline int
137 bpf_open(pcap_t *p, char *errbuf)
138 {
139 int fd;
140 int n = 0;
141 char device[sizeof "/dev/bpf0000000000"];
142
143 /*
144 * Go through all the minors and find one that isn't in use.
145 */
146 do {
147 (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++);
148 fd = open(device, O_RDONLY);
149 } while (fd < 0 && errno == EBUSY);
150
151 /*
152 * XXX better message for all minors used
153 */
154 if (fd < 0)
155 snprintf(errbuf, PCAP_ERRBUF_SIZE, "(no devices found) %s: %s",
156 device, pcap_strerror(errno));
157
158 return (fd);
159 }
160
161 pcap_t *
162 pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
163 {
164 int fd;
165 struct ifreq ifr;
166 struct bpf_version bv;
167 u_int v;
168 pcap_t *p;
169
170 p = (pcap_t *)malloc(sizeof(*p));
171 if (p == NULL) {
172 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
173 pcap_strerror(errno));
174 return (NULL);
175 }
176 bzero(p, sizeof(*p));
177 fd = bpf_open(p, ebuf);
178 if (fd < 0)
179 goto bad;
180
181 p->fd = fd;
182 p->snapshot = snaplen;
183
184 if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
185 snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s",
186 pcap_strerror(errno));
187 goto bad;
188 }
189 if (bv.bv_major != BPF_MAJOR_VERSION ||
190 bv.bv_minor < BPF_MINOR_VERSION) {
191 snprintf(ebuf, PCAP_ERRBUF_SIZE,
192 "kernel bpf filter out of date");
193 goto bad;
194 }
195 v = 32768; /* XXX this should be a user-accessible hook */
196 /* try finding a good size for the buffer */
197 do {
198 (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
199
200 (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
201 if ((ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) &&
202 (errno != ENOBUFS)) {
203 snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s",
204 errno, device, pcap_strerror(errno));
205 goto bad;
206 }
207 v >>= 2;
208 } while (fd < 0 && errno == ENOBUFS);
209
210 (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
211
212 (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
213 if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
214 snprintf(ebuf, PCAP_ERRBUF_SIZE, "%s: %s",
215 device, pcap_strerror(errno));
216 goto bad;
217 }
218 /* Get the data link layer type. */
219 if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
220 snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s",
221 pcap_strerror(errno));
222 goto bad;
223 }
224 #ifdef __OpenBSD__
225 switch (v) {
226 case DLT_LOOP:
227 v = DLT_NULL;
228 break;
229 }
230 #endif
231 #if _BSDI_VERSION - 0 >= 199510
232 /* The SLIP and PPP link layer header changed in BSD/OS 2.1 */
233 switch (v) {
234
235 case DLT_SLIP:
236 v = DLT_SLIP_BSDOS;
237 break;
238
239 case DLT_PPP:
240 v = DLT_PPP_BSDOS;
241 break;
242
243 case 11: /*DLT_FR*/
244 v = DLT_RAW; /*XXX*/
245 break;
246
247 case 12: /*DLT_C_HDLC*/
248 v = DLT_CHDLC;
249 break;
250 }
251 #endif
252 p->linktype = v;
253
254 /* set timeout */
255 if (to_ms != 0) {
256 struct timeval to;
257 to.tv_sec = to_ms / 1000;
258 to.tv_usec = (to_ms * 1000) % 1000000;
259 if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
260 snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s",
261 pcap_strerror(errno));
262 goto bad;
263 }
264 }
265
266 #ifdef BIOCIMMEDIATE
267 v = 1;
268 if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) {
269 snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCIMMEDIATE: %s",
270 pcap_strerror(errno));
271 goto bad;
272 }
273 #endif /* BIOCIMMEDIATE */
274
275 if (promisc)
276 /* set promiscuous mode, okay if it fails */
277 (void)ioctl(p->fd, BIOCPROMISC, NULL);
278
279 if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
280 snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s",
281 pcap_strerror(errno));
282 goto bad;
283 }
284 p->bufsize = v;
285 p->buffer = (u_char *)malloc(p->bufsize);
286 if (p->buffer == NULL) {
287 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
288 pcap_strerror(errno));
289 goto bad;
290 }
291
292 return (p);
293 bad:
294 (void)close(fd);
295 free(p);
296 return (NULL);
297 }
298
299 int
300 pcap_setfilter(pcap_t *p, struct bpf_program *fp)
301 {
302 /*
303 * It looks that BPF code generated by gen_protochain() is not
304 * compatible with some of kernel BPF code (for example BSD/OS 3.1).
305 * Take a safer side for now.
306 */
307 if (no_optimize)
308 p->fcode = *fp;
309 else if (p->sf.rfile != NULL)
310 p->fcode = *fp;
311 else if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) {
312 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s",
313 pcap_strerror(errno));
314 return (-1);
315 }
316 return (0);
317 }