1999-10-07 23:46:40 +00:00
|
|
|
/*
|
|
|
|
* Stanford Enetfilter subroutines for tcpdump
|
|
|
|
*
|
|
|
|
* Based on the MERIT NNstat etherifrt.c and the Ultrix pcap-pf.c
|
|
|
|
* subroutines.
|
|
|
|
*
|
|
|
|
* Rayan Zachariassen, CA*Net
|
|
|
|
*/
|
2000-01-10 18:42:59 +00:00
|
|
|
#ifndef lint
|
|
|
|
static const char rcsid[] =
|
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
|
|
|
"@(#) $Header: /tcpdump/master/libpcap/pcap-enet.c,v 1.4 2000-09-17 04:04:37 guy Exp $";
|
2000-07-11 00:37:04 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
2000-01-10 18:42:59 +00:00
|
|
|
#endif
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/bpf.h>
|
|
|
|
#include <net/enet.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/if_ether.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include "interface.h"
|
|
|
|
|
|
|
|
struct packet_header {
|
|
|
|
#ifdef IBMRTPC
|
|
|
|
struct LengthWords length;
|
|
|
|
struct tap_header tap;
|
|
|
|
#endif /* IBMRTPC */
|
|
|
|
u_char packet[8]
|
|
|
|
};
|
|
|
|
|
|
|
|
extern int errno;
|
|
|
|
|
|
|
|
#define BUFSPACE (4*1024)
|
|
|
|
|
|
|
|
/* Forwards */
|
|
|
|
static void efReadError(int, char *);
|
|
|
|
|
|
|
|
void
|
|
|
|
readloop(int cnt, int if_fd, struct bpf_program *fp, printfunc printit)
|
|
|
|
{
|
|
|
|
#ifdef IBMRTPC
|
|
|
|
register struct packet_header *ph;
|
|
|
|
register u_char *bp;
|
|
|
|
register int inc;
|
|
|
|
#else /* !IBMRTPC */
|
|
|
|
static struct timeval tv = { 0 };
|
|
|
|
#endif /* IBMRTPC */
|
|
|
|
register int cc, caplen;
|
|
|
|
register struct bpf_insn *fcode = fp->bf_insns;
|
|
|
|
union {
|
|
|
|
struct packet_header hdr;
|
|
|
|
u_char p[BUFSPACE];
|
|
|
|
u_short s;
|
|
|
|
} buf;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if ((cc = read(if_fd, (char *)buf.p, sizeof(buf))) < 0)
|
|
|
|
efReadError(if_fd, "reader");
|
|
|
|
|
|
|
|
#ifdef IBMRTPC
|
|
|
|
/*
|
|
|
|
* Loop through each packet.
|
|
|
|
*/
|
|
|
|
bp = buf.p;
|
|
|
|
while (cc > 0) {
|
|
|
|
ph = (struct packet_header *)bp;
|
|
|
|
caplen = ph->tap.th_wirelen > snaplen ? snaplen : ph->tap
|
|
|
|
.th_wirelen ;
|
|
|
|
if (bpf_filter(fcode, (char *)ph->packet,
|
|
|
|
ph->tap.th_wirelen, caplen)) {
|
|
|
|
if (cnt >= 0 && --cnt < 0)
|
|
|
|
goto out;
|
|
|
|
(*printit)((char *)ph->packet,
|
|
|
|
(struct timeval *)ph->tap.th_timestamp,
|
|
|
|
ph->tap.th_wirelen, caplen);
|
|
|
|
}
|
|
|
|
inc = ph->length.PacketOffset;
|
|
|
|
cc -= inc;
|
|
|
|
bp += inc;
|
|
|
|
}
|
|
|
|
#else /* !IBMRTPC */
|
|
|
|
caplen = cc > snaplen ? snaplen : cc ;
|
|
|
|
if (bpf_filter(fcode, buf.hdr.packet, cc, caplen)) {
|
|
|
|
if (cnt >= 0 && --cnt < 0)
|
|
|
|
goto out;
|
|
|
|
(*printit)(buf.hdr.packet, &tv, cc, caplen);
|
|
|
|
}
|
|
|
|
#endif /* IBMRTPC */
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
wrapup(if_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Call ONLY if read() has returned an error on packet filter */
|
|
|
|
static void
|
|
|
|
efReadError(int fid, char *msg)
|
|
|
|
{
|
|
|
|
if (errno == EINVAL) { /* read MAXINT bytes already! */
|
|
|
|
if (lseek(fid, 0, 0) < 0) {
|
|
|
|
perror("tcpdump: efReadError/lseek");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
(void) fprintf(stderr, "tcpdump: ");
|
|
|
|
perror(msg);
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
wrapup(int fd)
|
|
|
|
{
|
|
|
|
#ifdef IBMRTPC
|
|
|
|
struct enstats es;
|
|
|
|
|
|
|
|
if (ioctl(fd, EIOSTATS, &es) == -1) {
|
|
|
|
perror("tcpdump: enet ioctl EIOSTATS error");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "%d packets queued", es.enStat_Rcnt);
|
|
|
|
if (es.enStat_Rdrops > 0)
|
|
|
|
fprintf(stderr, ", %d dropped", es.enStat_Rdrops);
|
|
|
|
if (es.enStat_Reads > 0)
|
|
|
|
fprintf(stderr, ", %d tcpdump %s", es.enStat_Reads,
|
|
|
|
es.enStat_Reads > 1 ? "reads" : "read");
|
|
|
|
if (es.enStat_MaxRead > 1)
|
|
|
|
fprintf(stderr, ", %d packets in largest read",
|
|
|
|
es.enStat_MaxRead);
|
|
|
|
putc('\n', stderr);
|
|
|
|
#endif /* IBMRTPC */
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
initdevice(char *device, int pflag, int *linktype)
|
|
|
|
{
|
|
|
|
struct eniocb ctl;
|
|
|
|
struct enfilter filter;
|
|
|
|
u_int maxwaiting;
|
|
|
|
int if_fd;
|
|
|
|
|
|
|
|
#ifdef IBMRTPC
|
|
|
|
GETENETDEVICE(0, O_RDONLY, &if_fd);
|
|
|
|
#else /* !IBMRTPC */
|
|
|
|
if_fd = open("/dev/enet", O_RDONLY, 0);
|
|
|
|
#endif /* IBMRTPC */
|
|
|
|
|
|
|
|
if (if_fd == -1) {
|
|
|
|
perror("tcpdump: enet open error");
|
|
|
|
error(
|
|
|
|
"your system may not be properly configured; see \"man enet(4)\"");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get operating parameters. */
|
|
|
|
|
|
|
|
if (ioctl(if_fd, EIOCGETP, (char *)&ctl) == -1) {
|
|
|
|
perror("tcpdump: enet ioctl EIOCGETP error");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set operating parameters. */
|
|
|
|
|
|
|
|
#ifdef IBMRTPC
|
|
|
|
ctl.en_rtout = 1 * ctl.en_hz;
|
|
|
|
ctl.en_tr_etherhead = 1;
|
|
|
|
ctl.en_tap_network = 1;
|
|
|
|
ctl.en_multi_packet = 1;
|
|
|
|
ctl.en_maxlen = BUFSPACE;
|
|
|
|
#else /* !IBMRTPC */
|
|
|
|
ctl.en_rtout = 64; /* randomly picked value for HZ */
|
|
|
|
#endif /* IBMRTPC */
|
|
|
|
if (ioctl(if_fd, EIOCSETP, &ctl) == -1) {
|
|
|
|
perror("tcpdump: enet ioctl EIOCSETP error");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Flush the receive queue, since we've changed
|
|
|
|
the operating parameters and we otherwise might
|
|
|
|
receive data without headers. */
|
|
|
|
|
|
|
|
if (ioctl(if_fd, EIOCFLUSH) == -1) {
|
|
|
|
perror("tcpdump: enet ioctl EIOCFLUSH error");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the receive queue depth to its maximum. */
|
|
|
|
|
|
|
|
maxwaiting = ctl.en_maxwaiting;
|
|
|
|
if (ioctl(if_fd, EIOCSETW, &maxwaiting) == -1) {
|
|
|
|
perror("tcpdump: enet ioctl EIOCSETW error");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef IBMRTPC
|
|
|
|
/* Clear statistics. */
|
|
|
|
|
|
|
|
if (ioctl(if_fd, EIOCLRSTAT, 0) == -1) {
|
|
|
|
perror("tcpdump: enet ioctl EIOCLRSTAT error");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
#endif /* IBMRTPC */
|
|
|
|
|
|
|
|
/* Set the filter (accept all packets). */
|
|
|
|
|
|
|
|
filter.enf_Priority = 3;
|
|
|
|
filter.enf_FilterLen = 0;
|
|
|
|
if (ioctl(if_fd, EIOCSETF, &filter) == -1) {
|
|
|
|
perror("tcpdump: enet ioctl EIOCSETF error");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* "enetfilter" supports only ethernets.
|
|
|
|
*/
|
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
|
|
|
*linktype = PCAP_ENCAP_ETHERNET;
|
1999-10-07 23:46:40 +00:00
|
|
|
|
|
|
|
return(if_fd);
|
|
|
|
}
|