]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libpcap/pcap-bpf.c
This commit was generated by cvs2svn to compensate for changes in r50760,
[FreeBSD/FreeBSD.git] / contrib / 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: pcap-bpf.c,v 1.31 98/07/12 13:14:55 leres 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 int
51 pcap_stats(pcap_t *p, struct pcap_stat *ps)
52 {
53         struct bpf_stat s;
54
55         if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) {
56                 sprintf(p->errbuf, "BIOCGSTATS: %s", pcap_strerror(errno));
57                 return (-1);
58         }
59
60         ps->ps_recv = s.bs_recv;
61         ps->ps_drop = s.bs_drop;
62         return (0);
63 }
64
65 int
66 pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
67 {
68         int cc;
69         int n = 0;
70         register u_char *bp, *ep;
71
72  again:
73         cc = p->cc;
74         if (p->cc == 0) {
75                 cc = read(p->fd, (char *)p->buffer, p->bufsize);
76                 if (cc < 0) {
77                         /* Don't choke when we get ptraced */
78                         switch (errno) {
79
80                         case EINTR:
81                                 goto again;
82
83                         case EWOULDBLOCK:
84                                 return (0);
85 #if defined(sun) && !defined(BSD)
86                         /*
87                          * Due to a SunOS bug, after 2^31 bytes, the kernel
88                          * file offset overflows and read fails with EINVAL.
89                          * The lseek() to 0 will fix things.
90                          */
91                         case EINVAL:
92                                 if (lseek(p->fd, 0L, SEEK_CUR) +
93                                     p->bufsize < 0) {
94                                         (void)lseek(p->fd, 0L, SEEK_SET);
95                                         goto again;
96                                 }
97                                 /* fall through */
98 #endif
99                         }
100                         sprintf(p->errbuf, "read: %s", pcap_strerror(errno));
101                         return (-1);
102                 }
103                 bp = p->buffer;
104         } else
105                 bp = p->bp;
106
107         /*
108          * Loop through each packet.
109          */
110 #define bhp ((struct bpf_hdr *)bp)
111         ep = bp + cc;
112         while (bp < ep) {
113                 register int caplen, hdrlen;
114                 caplen = bhp->bh_caplen;
115                 hdrlen = bhp->bh_hdrlen;
116                 /*
117                  * XXX A bpf_hdr matches a pcap_pkthdr.
118                  */
119                 (*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen);
120                 bp += BPF_WORDALIGN(caplen + hdrlen);
121                 if (++n >= cnt && cnt > 0) {
122                         p->bp = bp;
123                         p->cc = ep - bp;
124                         return (n);
125                 }
126         }
127 #undef bhp
128         p->cc = 0;
129         return (n);
130 }
131
132 static inline int
133 bpf_open(pcap_t *p, char *errbuf)
134 {
135         int fd;
136         int n = 0;
137         char device[sizeof "/dev/bpf000"];
138
139         /*
140          * Go through all the minors and find one that isn't in use.
141          */
142         do {
143                 (void)sprintf(device, "/dev/bpf%d", n++);
144                 fd = open(device, O_RDONLY);
145         } while (fd < 0 && errno == EBUSY);
146
147         /*
148          * XXX better message for all minors used
149          */
150         if (fd < 0)
151                 sprintf(errbuf, "%s: %s", device, pcap_strerror(errno));
152
153         return (fd);
154 }
155
156 pcap_t *
157 pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
158 {
159         int fd;
160         struct ifreq ifr;
161         struct bpf_version bv;
162         u_int v;
163         pcap_t *p;
164
165         p = (pcap_t *)malloc(sizeof(*p));
166         if (p == NULL) {
167                 sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
168                 return (NULL);
169         }
170         bzero(p, sizeof(*p));
171         fd = bpf_open(p, ebuf);
172         if (fd < 0)
173                 goto bad;
174
175         p->fd = fd;
176         p->snapshot = snaplen;
177
178         if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
179                 sprintf(ebuf, "BIOCVERSION: %s", pcap_strerror(errno));
180                 goto bad;
181         }
182         if (bv.bv_major != BPF_MAJOR_VERSION ||
183             bv.bv_minor < BPF_MINOR_VERSION) {
184                 sprintf(ebuf, "kernel bpf filter out of date");
185                 goto bad;
186         }
187         v = 32768;      /* XXX this should be a user-accessible hook */
188         /* Ignore the return value - this is because the call fails on
189          * BPF systems that don't have kernel malloc.  And if the call
190          * fails, it's no big deal, we just continue to use the standard
191          * buffer size.
192          */
193         (void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
194
195         (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
196         if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
197                 sprintf(ebuf, "%s: %s", device, pcap_strerror(errno));
198                 goto bad;
199         }
200         /* Get the data link layer type. */
201         if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
202                 sprintf(ebuf, "BIOCGDLT: %s", pcap_strerror(errno));
203                 goto bad;
204         }
205 #if _BSDI_VERSION - 0 >= 199510
206         /* The SLIP and PPP link layer header changed in BSD/OS 2.1 */
207         switch (v) {
208
209         case DLT_SLIP:
210                 v = DLT_SLIP_BSDOS;
211                 break;
212
213         case DLT_PPP:
214                 v = DLT_PPP_BSDOS;
215                 break;
216         }
217 #endif
218         p->linktype = v;
219
220         /* set timeout */
221         if (to_ms != 0) {
222                 struct timeval to;
223                 to.tv_sec = to_ms / 1000;
224                 to.tv_usec = (to_ms * 1000) % 1000000;
225                 if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
226                         sprintf(ebuf, "BIOCSRTIMEOUT: %s",
227                                 pcap_strerror(errno));
228                         goto bad;
229                 }
230         }
231         if (promisc)
232                 /* set promiscuous mode, okay if it fails */
233                 (void)ioctl(p->fd, BIOCPROMISC, NULL);
234
235         if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
236                 sprintf(ebuf, "BIOCGBLEN: %s", pcap_strerror(errno));
237                 goto bad;
238         }
239         p->bufsize = v;
240         p->buffer = (u_char *)malloc(p->bufsize);
241         if (p->buffer == NULL) {
242                 sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
243                 goto bad;
244         }
245
246         return (p);
247  bad:
248         (void)close(fd);
249         free(p);
250         return (NULL);
251 }
252
253 int
254 pcap_setfilter(pcap_t *p, struct bpf_program *fp)
255 {
256         if (p->sf.rfile != NULL)
257                 p->fcode = *fp;
258         else if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) {
259                 sprintf(p->errbuf, "BIOCSETF: %s", pcap_strerror(errno));
260                 return (-1);
261         }
262         return (0);
263 }