1999-10-07 23:46:40 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1993, 1994, 1995, 1996, 1998
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that: (1) source code distributions
|
|
|
|
* retain the above copyright notice and this paragraph in its entirety, (2)
|
|
|
|
* distributions including binary code include the above copyright notice and
|
|
|
|
* this paragraph in its entirety in the documentation or other materials
|
|
|
|
* provided with the distribution, and (3) all advertising materials mentioning
|
|
|
|
* features or use of this software display the following acknowledgement:
|
|
|
|
* ``This product includes software developed by the University of California,
|
|
|
|
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
|
|
|
|
* the University nor the names of its contributors may be used to endorse
|
|
|
|
* or promote products derived from this software without specific prior
|
|
|
|
* written permission.
|
|
|
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
|
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
*/
|
|
|
|
#ifndef lint
|
|
|
|
static const char rcsid[] =
|
2001-11-17 21:24:09 +00:00
|
|
|
"@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.47 2001-11-17 21:24:09 guy Exp $ (LBL)";
|
2000-07-11 00:37:04 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
1999-10-07 23:46:40 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <sys/param.h> /* optionally get BSD define */
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/timeb.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
|
|
|
#include <net/if.h>
|
2001-11-17 21:24:09 +00:00
|
|
|
#ifdef _AIX
|
|
|
|
/*
|
|
|
|
* XXX - I'm guessing here AIX defines IFT_ values in <net/if_types.h>,
|
|
|
|
* as BSD does. If not, this code won't compile, but, if not, you
|
|
|
|
* want to send us a bug report and fall back on using DLPI.
|
|
|
|
* It's not as if BPF used to work right on AIX before this change;
|
|
|
|
* this change attempts to fix the fact that it didn't....
|
|
|
|
*/
|
|
|
|
#include <net/if_types.h> /* for IFT_ values */
|
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "pcap-int.h"
|
|
|
|
|
|
|
|
#ifdef HAVE_OS_PROTO_H
|
|
|
|
#include "os-proto.h"
|
|
|
|
#endif
|
|
|
|
|
1999-10-19 15:18:28 +00:00
|
|
|
#include "gencode.h"
|
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
int
|
|
|
|
pcap_stats(pcap_t *p, struct pcap_stat *ps)
|
|
|
|
{
|
|
|
|
struct bpf_stat s;
|
|
|
|
|
2001-07-29 01:22:40 +00:00
|
|
|
/*
|
|
|
|
* "ps_recv" counts packets handed to the filter, not packets
|
|
|
|
* that passed the filter.
|
|
|
|
*
|
|
|
|
* "ps_drop" counts packets dropped inside the BPF device
|
|
|
|
* because we ran out of buffer space. It doesn't count
|
|
|
|
* packets dropped by the interface driver. It counts
|
|
|
|
* only packets that passed the filter.
|
|
|
|
*/
|
1999-10-07 23:46:40 +00:00
|
|
|
if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCGSTATS: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
ps->ps_recv = s.bs_recv;
|
|
|
|
ps->ps_drop = s.bs_drop;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
|
|
|
|
{
|
|
|
|
int cc;
|
|
|
|
int n = 0;
|
|
|
|
register u_char *bp, *ep;
|
|
|
|
|
|
|
|
again:
|
|
|
|
cc = p->cc;
|
|
|
|
if (p->cc == 0) {
|
|
|
|
cc = read(p->fd, (char *)p->buffer, p->bufsize);
|
|
|
|
if (cc < 0) {
|
|
|
|
/* Don't choke when we get ptraced */
|
|
|
|
switch (errno) {
|
|
|
|
|
|
|
|
case EINTR:
|
|
|
|
goto again;
|
|
|
|
|
|
|
|
case EWOULDBLOCK:
|
|
|
|
return (0);
|
|
|
|
#if defined(sun) && !defined(BSD)
|
|
|
|
/*
|
|
|
|
* Due to a SunOS bug, after 2^31 bytes, the kernel
|
|
|
|
* file offset overflows and read fails with EINVAL.
|
|
|
|
* The lseek() to 0 will fix things.
|
|
|
|
*/
|
|
|
|
case EINVAL:
|
|
|
|
if (lseek(p->fd, 0L, SEEK_CUR) +
|
|
|
|
p->bufsize < 0) {
|
|
|
|
(void)lseek(p->fd, 0L, SEEK_SET);
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
/* fall through */
|
|
|
|
#endif
|
|
|
|
}
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
bp = p->buffer;
|
|
|
|
} else
|
|
|
|
bp = p->bp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop through each packet.
|
|
|
|
*/
|
|
|
|
#define bhp ((struct bpf_hdr *)bp)
|
|
|
|
ep = bp + cc;
|
|
|
|
while (bp < ep) {
|
|
|
|
register int caplen, hdrlen;
|
|
|
|
caplen = bhp->bh_caplen;
|
|
|
|
hdrlen = bhp->bh_hdrlen;
|
|
|
|
/*
|
|
|
|
* XXX A bpf_hdr matches a pcap_pkthdr.
|
|
|
|
*/
|
2001-11-17 21:24:09 +00:00
|
|
|
#ifdef _AIX
|
|
|
|
/*
|
|
|
|
* AIX's BPF returns seconds/nanoseconds time stamps, not
|
|
|
|
* seconds/microseconds time stamps.
|
|
|
|
*
|
|
|
|
* XXX - I'm guessing here that it's a "struct timestamp";
|
|
|
|
* if not, this code won't compile, but, if not, you
|
|
|
|
* want to send us a bug report and fall back on using
|
|
|
|
* DLPI. It's not as if BPF used to work right on
|
|
|
|
* AIX before this change; this change attempts to fix
|
|
|
|
* the fact that it didn't....
|
|
|
|
*/
|
|
|
|
bhp->bh_tstamp.tv_usec = bhp->bh_tstamp.tv_usec/1000;
|
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
(*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen);
|
|
|
|
bp += BPF_WORDALIGN(caplen + hdrlen);
|
|
|
|
if (++n >= cnt && cnt > 0) {
|
|
|
|
p->bp = bp;
|
|
|
|
p->cc = ep - bp;
|
|
|
|
return (n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#undef bhp
|
|
|
|
p->cc = 0;
|
|
|
|
return (n);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
bpf_open(pcap_t *p, char *errbuf)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int n = 0;
|
2000-04-27 09:11:11 +00:00
|
|
|
char device[sizeof "/dev/bpf0000000000"];
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Go through all the minors and find one that isn't in use.
|
|
|
|
*/
|
|
|
|
do {
|
2000-04-27 09:11:11 +00:00
|
|
|
(void)snprintf(device, sizeof(device), "/dev/bpf%d", n++);
|
1999-10-07 23:46:40 +00:00
|
|
|
fd = open(device, O_RDONLY);
|
|
|
|
} while (fd < 0 && errno == EBUSY);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX better message for all minors used
|
|
|
|
*/
|
|
|
|
if (fd < 0)
|
2000-07-10 04:50:05 +00:00
|
|
|
snprintf(errbuf, PCAP_ERRBUF_SIZE, "(no devices found) %s: %s",
|
2000-04-27 09:11:11 +00:00
|
|
|
device, pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
return (fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
pcap_t *
|
|
|
|
pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
struct ifreq ifr;
|
|
|
|
struct bpf_version bv;
|
|
|
|
u_int v;
|
|
|
|
pcap_t *p;
|
|
|
|
|
|
|
|
p = (pcap_t *)malloc(sizeof(*p));
|
|
|
|
if (p == NULL) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
return (NULL);
|
|
|
|
}
|
2000-07-29 08:03:56 +00:00
|
|
|
memset(p, 0, sizeof(*p));
|
1999-10-07 23:46:40 +00:00
|
|
|
fd = bpf_open(p, ebuf);
|
|
|
|
if (fd < 0)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
p->fd = fd;
|
|
|
|
p->snapshot = snaplen;
|
|
|
|
|
|
|
|
if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
if (bv.bv_major != BPF_MAJOR_VERSION ||
|
|
|
|
bv.bv_minor < BPF_MINOR_VERSION) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"kernel bpf filter out of date");
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
2000-07-11 23:00:05 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Try finding a good size for the buffer; 32768 may be too
|
|
|
|
* big, so keep cutting it in half until we find a size
|
|
|
|
* that works, or run out of sizes to try.
|
2000-07-11 23:02:51 +00:00
|
|
|
*
|
|
|
|
* XXX - there should be a user-accessible hook to set the
|
|
|
|
* initial buffer size.
|
2000-07-11 23:00:05 +00:00
|
|
|
*/
|
2000-07-11 23:02:51 +00:00
|
|
|
for (v = 32768; v != 0; v >>= 1) {
|
2000-07-11 23:00:05 +00:00
|
|
|
/* Ignore the return value - this is because the call fails
|
|
|
|
* on BPF systems that don't have kernel malloc. And if
|
|
|
|
* the call fails, it's no big deal, we just continue to
|
|
|
|
* use the standard buffer size.
|
|
|
|
*/
|
|
|
|
(void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
|
|
|
|
|
|
|
|
(void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
|
|
|
|
if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
|
|
|
|
break; /* that size worked; we're done */
|
|
|
|
|
|
|
|
if (errno != ENOBUFS) {
|
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSETIF: %s: %s",
|
|
|
|
device, pcap_strerror(errno));
|
|
|
|
goto bad;
|
|
|
|
}
|
2000-07-11 23:02:51 +00:00
|
|
|
}
|
2000-07-11 23:00:05 +00:00
|
|
|
|
|
|
|
if (v == 0) {
|
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE,
|
|
|
|
"BIOCSBLEN: %s: No buffer size worked", device);
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
2000-07-11 23:00:05 +00:00
|
|
|
|
1999-10-07 23:46:40 +00:00
|
|
|
/* Get the data link layer type. */
|
|
|
|
if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
2001-11-17 21:24:09 +00:00
|
|
|
#ifdef _AIX
|
|
|
|
/*
|
|
|
|
* AIX's BPF returns IFF_ types, not DLT_ types, in BIOCGDLT.
|
|
|
|
*/
|
1999-10-19 15:18:28 +00:00
|
|
|
switch (v) {
|
2001-11-17 21:24:09 +00:00
|
|
|
|
|
|
|
case IFT_ETHER:
|
|
|
|
case IFT_ISO88023:
|
|
|
|
v = DLT_EN10MB;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IFT_FDDI:
|
|
|
|
v = DLT_FDDI;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IFT_ISO88025:
|
|
|
|
v = DLT_IEEE802;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
Introduce a set of PCAP_ENCAP_ codes to specify packet encapsulations.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that are
(believed to be) the same in all BSDs, the PCAP_ENCAP_ codes have the
same values as the corresponding DLT_ codes.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that were added
in libpcap 0.5 as "non-kernel" DLT_ codes, or had their values changed
in libpcap 0.5 in order to cope with the fact that those DLT_ codes
have different values in different systems, the PCAP_ENCAP_ codes have
the same values as the corresponding DLT_ codes.
We add some additional PCAP_ENCAP_ codes to handle IEEE 802.11 (which
currently has its link-layer information turned into an Ethernet header
by at least some of the BSDs, but John Hawkinson at MIT wants to add a
DLT_ value for 802.11 and pass up the full link-layer header) and the
Classical IP encapsulation for ATM on Linux (which isn't always the same
as DLT_ATM_RFC1483, from what I can tell, alas).
"pcap-bpf.c" maps DLT_ codes to PCAP_ENCAP_ codes, so as not to supply
to libpcap's callers any DLT_ codes other than the ones that have the
same values on all platforms; it supplies PCAP_ENCAP_ codes for all
others.
In libpcap's "bpf/net/bpf.h", we define the DLT_ values that aren't the
same on all platforms with the new values starting at 100 (to keep them
out of the way of the values various BSDs might assign to them), as we
did in 0.5, but do so only if they're not already defined; platforms
with <net/bpf.h> headers that come with the kernel (e.g., the BSDs)
should define them with the values that they have always had on that
platform, *not* with the values we used in 0.5.
(Code using this version of libpcap should check for the new PCAP_ENCAP_
codes; those are given the values that the corresponding DLT_ values had
in 0.5, so code that checks for them will handle 0.5 libpcap files
correctly even if the platform defines DLT_RAW, say, as something other
than 101. If that code also checks for DLT_RAW - which means it can't
just use a switch statement, as DLT_RAW might be defined as 101 if the
platform doesn't itself define DLT_RAW with some other value - then it
will also handle old DLT_RAW captures, as long as they were made on the
same platform or on another platform that used the same value for
DLT_RAW. It can't handle captures from a platform that uses that value
for another DLT_ code, but that's always been the case, and isn't easily
fixable.)
The intent here is to decouple the values that are returned by
"pcap_datalink()" and put into the header of tcpdump/libpcap save files
from the DLT_ values returned by BIOCGDLT in BSD kernels, allowing the
BSDs to assign values to DLT_ codes, in their kernels, as they choose,
without creating more incompatibilities between tcpdump/libpcap save
files from different platforms.
2000-09-17 04:04:36 +00:00
|
|
|
/*
|
2001-11-17 21:24:09 +00:00
|
|
|
* We don't know what to map this to yet.
|
Introduce a set of PCAP_ENCAP_ codes to specify packet encapsulations.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that are
(believed to be) the same in all BSDs, the PCAP_ENCAP_ codes have the
same values as the corresponding DLT_ codes.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that were added
in libpcap 0.5 as "non-kernel" DLT_ codes, or had their values changed
in libpcap 0.5 in order to cope with the fact that those DLT_ codes
have different values in different systems, the PCAP_ENCAP_ codes have
the same values as the corresponding DLT_ codes.
We add some additional PCAP_ENCAP_ codes to handle IEEE 802.11 (which
currently has its link-layer information turned into an Ethernet header
by at least some of the BSDs, but John Hawkinson at MIT wants to add a
DLT_ value for 802.11 and pass up the full link-layer header) and the
Classical IP encapsulation for ATM on Linux (which isn't always the same
as DLT_ATM_RFC1483, from what I can tell, alas).
"pcap-bpf.c" maps DLT_ codes to PCAP_ENCAP_ codes, so as not to supply
to libpcap's callers any DLT_ codes other than the ones that have the
same values on all platforms; it supplies PCAP_ENCAP_ codes for all
others.
In libpcap's "bpf/net/bpf.h", we define the DLT_ values that aren't the
same on all platforms with the new values starting at 100 (to keep them
out of the way of the values various BSDs might assign to them), as we
did in 0.5, but do so only if they're not already defined; platforms
with <net/bpf.h> headers that come with the kernel (e.g., the BSDs)
should define them with the values that they have always had on that
platform, *not* with the values we used in 0.5.
(Code using this version of libpcap should check for the new PCAP_ENCAP_
codes; those are given the values that the corresponding DLT_ values had
in 0.5, so code that checks for them will handle 0.5 libpcap files
correctly even if the platform defines DLT_RAW, say, as something other
than 101. If that code also checks for DLT_RAW - which means it can't
just use a switch statement, as DLT_RAW might be defined as 101 if the
platform doesn't itself define DLT_RAW with some other value - then it
will also handle old DLT_RAW captures, as long as they were made on the
same platform or on another platform that used the same value for
DLT_RAW. It can't handle captures from a platform that uses that value
for another DLT_ code, but that's always been the case, and isn't easily
fixable.)
The intent here is to decouple the values that are returned by
"pcap_datalink()" and put into the header of tcpdump/libpcap save files
from the DLT_ values returned by BIOCGDLT in BSD kernels, allowing the
BSDs to assign values to DLT_ codes, in their kernels, as they choose,
without creating more incompatibilities between tcpdump/libpcap save
files from different platforms.
2000-09-17 04:04:36 +00:00
|
|
|
*/
|
2001-11-17 21:24:09 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown interface type %lu",
|
|
|
|
v);
|
|
|
|
goto bad;
|
Get rid of the PCAP_ENCAP_ values - if an application uses them, that
application won't build with any other version of libpcap, which means
that a lot of applications won't use them. In addition,
"pcap_linktype()" needs to return DLT_ values, so that platforms that
build libpcap as a shared library won't break binary compatibility if
they update to this version of libpcap.
Instead, we map from DLT_ values to LINKTYPE_ values when writing
savefiles, and map from LINKTYPE_ values to DLT_ values when reading
savefiles, so that savefiles don't have platform-dependent DLT_ values
in the header as the link type, they have platform-independent LINKTYPE_
values.
This means we don't need to make DLT_ATM_RFC1483, DLT_RAW, etc. have
platform-independent values starting at 100 - only the values in the
savefile header need to be like that.
2000-10-12 03:53:57 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if _BSDI_VERSION - 0 >= 199510
|
|
|
|
/* The SLIP and PPP link layer header changed in BSD/OS 2.1 */
|
|
|
|
switch (v) {
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
case DLT_SLIP:
|
Get rid of the PCAP_ENCAP_ values - if an application uses them, that
application won't build with any other version of libpcap, which means
that a lot of applications won't use them. In addition,
"pcap_linktype()" needs to return DLT_ values, so that platforms that
build libpcap as a shared library won't break binary compatibility if
they update to this version of libpcap.
Instead, we map from DLT_ values to LINKTYPE_ values when writing
savefiles, and map from LINKTYPE_ values to DLT_ values when reading
savefiles, so that savefiles don't have platform-dependent DLT_ values
in the header as the link type, they have platform-independent LINKTYPE_
values.
This means we don't need to make DLT_ATM_RFC1483, DLT_RAW, etc. have
platform-independent values starting at 100 - only the values in the
savefile header need to be like that.
2000-10-12 03:53:57 +00:00
|
|
|
v = DLT_SLIP_BSDOS;
|
1999-10-07 23:46:40 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DLT_PPP:
|
Get rid of the PCAP_ENCAP_ values - if an application uses them, that
application won't build with any other version of libpcap, which means
that a lot of applications won't use them. In addition,
"pcap_linktype()" needs to return DLT_ values, so that platforms that
build libpcap as a shared library won't break binary compatibility if
they update to this version of libpcap.
Instead, we map from DLT_ values to LINKTYPE_ values when writing
savefiles, and map from LINKTYPE_ values to DLT_ values when reading
savefiles, so that savefiles don't have platform-dependent DLT_ values
in the header as the link type, they have platform-independent LINKTYPE_
values.
This means we don't need to make DLT_ATM_RFC1483, DLT_RAW, etc. have
platform-independent values starting at 100 - only the values in the
savefile header need to be like that.
2000-10-12 03:53:57 +00:00
|
|
|
v = DLT_PPP_BSDOS;
|
1999-10-07 23:46:40 +00:00
|
|
|
break;
|
1999-10-19 15:18:28 +00:00
|
|
|
|
Get rid of the PCAP_ENCAP_ values - if an application uses them, that
application won't build with any other version of libpcap, which means
that a lot of applications won't use them. In addition,
"pcap_linktype()" needs to return DLT_ values, so that platforms that
build libpcap as a shared library won't break binary compatibility if
they update to this version of libpcap.
Instead, we map from DLT_ values to LINKTYPE_ values when writing
savefiles, and map from LINKTYPE_ values to DLT_ values when reading
savefiles, so that savefiles don't have platform-dependent DLT_ values
in the header as the link type, they have platform-independent LINKTYPE_
values.
This means we don't need to make DLT_ATM_RFC1483, DLT_RAW, etc. have
platform-independent values starting at 100 - only the values in the
savefile header need to be like that.
2000-10-12 03:53:57 +00:00
|
|
|
case 11: /*DLT_FR*/
|
|
|
|
v = DLT_RAW; /*XXX*/
|
1999-10-19 15:18:28 +00:00
|
|
|
break;
|
Introduce a set of PCAP_ENCAP_ codes to specify packet encapsulations.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that are
(believed to be) the same in all BSDs, the PCAP_ENCAP_ codes have the
same values as the corresponding DLT_ codes.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that were added
in libpcap 0.5 as "non-kernel" DLT_ codes, or had their values changed
in libpcap 0.5 in order to cope with the fact that those DLT_ codes
have different values in different systems, the PCAP_ENCAP_ codes have
the same values as the corresponding DLT_ codes.
We add some additional PCAP_ENCAP_ codes to handle IEEE 802.11 (which
currently has its link-layer information turned into an Ethernet header
by at least some of the BSDs, but John Hawkinson at MIT wants to add a
DLT_ value for 802.11 and pass up the full link-layer header) and the
Classical IP encapsulation for ATM on Linux (which isn't always the same
as DLT_ATM_RFC1483, from what I can tell, alas).
"pcap-bpf.c" maps DLT_ codes to PCAP_ENCAP_ codes, so as not to supply
to libpcap's callers any DLT_ codes other than the ones that have the
same values on all platforms; it supplies PCAP_ENCAP_ codes for all
others.
In libpcap's "bpf/net/bpf.h", we define the DLT_ values that aren't the
same on all platforms with the new values starting at 100 (to keep them
out of the way of the values various BSDs might assign to them), as we
did in 0.5, but do so only if they're not already defined; platforms
with <net/bpf.h> headers that come with the kernel (e.g., the BSDs)
should define them with the values that they have always had on that
platform, *not* with the values we used in 0.5.
(Code using this version of libpcap should check for the new PCAP_ENCAP_
codes; those are given the values that the corresponding DLT_ values had
in 0.5, so code that checks for them will handle 0.5 libpcap files
correctly even if the platform defines DLT_RAW, say, as something other
than 101. If that code also checks for DLT_RAW - which means it can't
just use a switch statement, as DLT_RAW might be defined as 101 if the
platform doesn't itself define DLT_RAW with some other value - then it
will also handle old DLT_RAW captures, as long as they were made on the
same platform or on another platform that used the same value for
DLT_RAW. It can't handle captures from a platform that uses that value
for another DLT_ code, but that's always been the case, and isn't easily
fixable.)
The intent here is to decouple the values that are returned by
"pcap_datalink()" and put into the header of tcpdump/libpcap save files
from the DLT_ values returned by BIOCGDLT in BSD kernels, allowing the
BSDs to assign values to DLT_ codes, in their kernels, as they choose,
without creating more incompatibilities between tcpdump/libpcap save
files from different platforms.
2000-09-17 04:04:36 +00:00
|
|
|
|
Get rid of the PCAP_ENCAP_ values - if an application uses them, that
application won't build with any other version of libpcap, which means
that a lot of applications won't use them. In addition,
"pcap_linktype()" needs to return DLT_ values, so that platforms that
build libpcap as a shared library won't break binary compatibility if
they update to this version of libpcap.
Instead, we map from DLT_ values to LINKTYPE_ values when writing
savefiles, and map from LINKTYPE_ values to DLT_ values when reading
savefiles, so that savefiles don't have platform-dependent DLT_ values
in the header as the link type, they have platform-independent LINKTYPE_
values.
This means we don't need to make DLT_ATM_RFC1483, DLT_RAW, etc. have
platform-independent values starting at 100 - only the values in the
savefile header need to be like that.
2000-10-12 03:53:57 +00:00
|
|
|
case 12: /*DLT_C_HDLC*/
|
|
|
|
v = DLT_CHDLC;
|
Introduce a set of PCAP_ENCAP_ codes to specify packet encapsulations.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that are
(believed to be) the same in all BSDs, the PCAP_ENCAP_ codes have the
same values as the corresponding DLT_ codes.
For those PCAP_ENCAP_ codes corresponding to DLT_ codes that were added
in libpcap 0.5 as "non-kernel" DLT_ codes, or had their values changed
in libpcap 0.5 in order to cope with the fact that those DLT_ codes
have different values in different systems, the PCAP_ENCAP_ codes have
the same values as the corresponding DLT_ codes.
We add some additional PCAP_ENCAP_ codes to handle IEEE 802.11 (which
currently has its link-layer information turned into an Ethernet header
by at least some of the BSDs, but John Hawkinson at MIT wants to add a
DLT_ value for 802.11 and pass up the full link-layer header) and the
Classical IP encapsulation for ATM on Linux (which isn't always the same
as DLT_ATM_RFC1483, from what I can tell, alas).
"pcap-bpf.c" maps DLT_ codes to PCAP_ENCAP_ codes, so as not to supply
to libpcap's callers any DLT_ codes other than the ones that have the
same values on all platforms; it supplies PCAP_ENCAP_ codes for all
others.
In libpcap's "bpf/net/bpf.h", we define the DLT_ values that aren't the
same on all platforms with the new values starting at 100 (to keep them
out of the way of the values various BSDs might assign to them), as we
did in 0.5, but do so only if they're not already defined; platforms
with <net/bpf.h> headers that come with the kernel (e.g., the BSDs)
should define them with the values that they have always had on that
platform, *not* with the values we used in 0.5.
(Code using this version of libpcap should check for the new PCAP_ENCAP_
codes; those are given the values that the corresponding DLT_ values had
in 0.5, so code that checks for them will handle 0.5 libpcap files
correctly even if the platform defines DLT_RAW, say, as something other
than 101. If that code also checks for DLT_RAW - which means it can't
just use a switch statement, as DLT_RAW might be defined as 101 if the
platform doesn't itself define DLT_RAW with some other value - then it
will also handle old DLT_RAW captures, as long as they were made on the
same platform or on another platform that used the same value for
DLT_RAW. It can't handle captures from a platform that uses that value
for another DLT_ code, but that's always been the case, and isn't easily
fixable.)
The intent here is to decouple the values that are returned by
"pcap_datalink()" and put into the header of tcpdump/libpcap save files
from the DLT_ values returned by BIOCGDLT in BSD kernels, allowing the
BSDs to assign values to DLT_ codes, in their kernels, as they choose,
without creating more incompatibilities between tcpdump/libpcap save
files from different platforms.
2000-09-17 04:04:36 +00:00
|
|
|
break;
|
|
|
|
}
|
Get rid of the PCAP_ENCAP_ values - if an application uses them, that
application won't build with any other version of libpcap, which means
that a lot of applications won't use them. In addition,
"pcap_linktype()" needs to return DLT_ values, so that platforms that
build libpcap as a shared library won't break binary compatibility if
they update to this version of libpcap.
Instead, we map from DLT_ values to LINKTYPE_ values when writing
savefiles, and map from LINKTYPE_ values to DLT_ values when reading
savefiles, so that savefiles don't have platform-dependent DLT_ values
in the header as the link type, they have platform-independent LINKTYPE_
values.
This means we don't need to make DLT_ATM_RFC1483, DLT_RAW, etc. have
platform-independent values starting at 100 - only the values in the
savefile header need to be like that.
2000-10-12 03:53:57 +00:00
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
p->linktype = v;
|
|
|
|
|
|
|
|
/* set timeout */
|
|
|
|
if (to_ms != 0) {
|
|
|
|
struct timeval to;
|
|
|
|
to.tv_sec = to_ms / 1000;
|
|
|
|
to.tv_usec = (to_ms * 1000) % 1000000;
|
|
|
|
if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
}
|
2000-07-10 04:50:05 +00:00
|
|
|
|
2000-07-14 06:25:49 +00:00
|
|
|
#ifdef _AIX
|
2000-07-10 04:50:05 +00:00
|
|
|
#ifdef BIOCIMMEDIATE
|
2000-07-14 06:25:49 +00:00
|
|
|
/*
|
|
|
|
* Darren Reed notes that
|
|
|
|
*
|
|
|
|
* On AIX (4.2 at least), if BIOCIMMEDIATE is not set, the
|
|
|
|
* timeout appears to be ignored and it waits until the buffer
|
|
|
|
* is filled before returning. The result of not having it
|
|
|
|
* set is almost worse than useless if your BPF filter
|
|
|
|
* is reducing things to only a few packets (i.e. one every
|
|
|
|
* second or so).
|
|
|
|
*
|
|
|
|
* so we turn BIOCIMMEDIATE mode on if this is AIX.
|
|
|
|
*
|
|
|
|
* We don't turn it on for other platforms, as that means we
|
|
|
|
* get woken up for every packet, which may not be what we want;
|
|
|
|
* in the Winter 1993 USENIX paper on BPF, they say:
|
|
|
|
*
|
|
|
|
* Since a process might want to look at every packet on a
|
|
|
|
* network and the time between packets can be only a few
|
|
|
|
* microseconds, it is not possible to do a read system call
|
|
|
|
* per packet and BPF must collect the data from several
|
|
|
|
* packets and return it as a unit when the monitoring
|
|
|
|
* application does a read.
|
|
|
|
*
|
|
|
|
* which I infer is the reason for the timeout - it means we
|
|
|
|
* wait that amount of time, in the hopes that more packets
|
|
|
|
* will arrive and we'll get them all with one read.
|
|
|
|
*
|
|
|
|
* Setting BIOCIMMEDIATE mode on FreeBSD (and probably other
|
|
|
|
* BSDs) causes the timeout to be ignored.
|
|
|
|
*
|
|
|
|
* On the other hand, some platforms (e.g., Linux) don't support
|
|
|
|
* timeouts, they just hand stuff to you as soon as it arrives;
|
|
|
|
* if that doesn't cause a problem on those platforms, it may
|
|
|
|
* be OK to have BIOCIMMEDIATE mode on BSD as well.
|
|
|
|
*
|
|
|
|
* (Note, though, that applications may depend on the read
|
|
|
|
* completing, even if no packets have arrived, when the timeout
|
|
|
|
* expires, e.g. GUI applications that have to check for input
|
|
|
|
* while waiting for packets to arrive; a non-zero timeout
|
|
|
|
* prevents "select()" from working right on FreeBSD and
|
|
|
|
* possibly other BSDs, as the timer doesn't start until a
|
|
|
|
* "read()" is done, so the timer isn't in effect if the
|
|
|
|
* application is blocked on a "select()", and the "select()"
|
|
|
|
* doesn't get woken up for a BPF device until the buffer
|
|
|
|
* fills up.)
|
|
|
|
*/
|
2000-07-10 04:50:05 +00:00
|
|
|
v = 1;
|
|
|
|
if (ioctl(p->fd, BIOCIMMEDIATE, &v) < 0) {
|
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCIMMEDIATE: %s",
|
|
|
|
pcap_strerror(errno));
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
#endif /* BIOCIMMEDIATE */
|
2000-07-14 06:25:49 +00:00
|
|
|
#endif /* _AIX */
|
2000-07-10 04:50:05 +00:00
|
|
|
|
2001-04-30 16:10:51 +00:00
|
|
|
if (promisc) {
|
1999-10-07 23:46:40 +00:00
|
|
|
/* set promiscuous mode, okay if it fails */
|
2001-04-30 16:10:51 +00:00
|
|
|
if (ioctl(p->fd, BIOCPROMISC, NULL) < 0) {
|
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCPROMISC: %s",
|
|
|
|
pcap_strerror(errno));
|
|
|
|
}
|
|
|
|
}
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
p->bufsize = v;
|
|
|
|
p->buffer = (u_char *)malloc(p->bufsize);
|
|
|
|
if (p->buffer == NULL) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (p);
|
|
|
|
bad:
|
|
|
|
(void)close(fd);
|
|
|
|
free(p);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcap_setfilter(pcap_t *p, struct bpf_program *fp)
|
|
|
|
{
|
1999-10-19 15:18:28 +00:00
|
|
|
/*
|
|
|
|
* It looks that BPF code generated by gen_protochain() is not
|
|
|
|
* compatible with some of kernel BPF code (for example BSD/OS 3.1).
|
|
|
|
* Take a safer side for now.
|
|
|
|
*/
|
2000-10-28 00:01:26 +00:00
|
|
|
if (no_optimize) {
|
|
|
|
if (install_bpf_program(p, fp) < 0)
|
|
|
|
return (-1);
|
|
|
|
} else if (p->sf.rfile != NULL) {
|
|
|
|
if (install_bpf_program(p, fp) < 0)
|
|
|
|
return (-1);
|
|
|
|
} else if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) {
|
2000-04-27 09:11:11 +00:00
|
|
|
snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "BIOCSETF: %s",
|
|
|
|
pcap_strerror(errno));
|
1999-10-07 23:46:40 +00:00
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|