dect
/
libpcap
Archived
13
0
Fork 0
This repository has been archived on 2022-02-17. You can view files and clone it, but cannot push or open issues or pull requests.
libpcap/pcap-nit.c

251 lines
5.7 KiB
C
Raw Normal View History

1999-10-07 23:46:40 +00:00
/*
* Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996
* 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[] =
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-nit.c,v 1.37 2000-09-17 04:04:37 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
1999-10-07 23:46:40 +00:00
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/nit.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <netinet/ip_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <netinet/tcp.h>
#include <netinet/tcpip.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include "pcap-int.h"
#ifdef HAVE_OS_PROTO_H
#include "os-proto.h"
#endif
/*
* The chunk size for NIT. This is the amount of buffering
* done for read calls.
*/
#define CHUNKSIZE (2*1024)
/*
* The total buffer space used by NIT.
*/
#define BUFSPACE (4*CHUNKSIZE)
/* Forwards */
static int nit_setflags(int, int, int, char *);
int
pcap_stats(pcap_t *p, struct pcap_stat *ps)
{
*ps = p->md.stat;
return (0);
}
int
pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
register int cc, n;
register struct bpf_insn *fcode = p->fcode.bf_insns;
register u_char *bp, *cp, *ep;
register struct nit_hdr *nh;
register int caplen;
cc = p->cc;
if (cc == 0) {
cc = read(p->fd, (char *)p->buffer, p->bufsize);
if (cc < 0) {
if (errno == EWOULDBLOCK)
return (0);
snprintf(p->errbuf, sizeof(p->errbuf), "pcap_read: %s",
1999-10-07 23:46:40 +00:00
pcap_strerror(errno));
return (-1);
}
bp = p->buffer;
} else
bp = p->bp;
/*
* Loop through each packet. The increment expression
* rounds up to the next int boundary past the end of
* the previous packet.
*/
n = 0;
ep = bp + cc;
while (bp < ep) {
nh = (struct nit_hdr *)bp;
cp = bp + sizeof(*nh);
switch (nh->nh_state) {
case NIT_CATCH:
break;
case NIT_NOMBUF:
case NIT_NOCLUSTER:
case NIT_NOSPACE:
p->md.stat.ps_drop = nh->nh_dropped;
continue;
case NIT_SEQNO:
continue;
default:
snprintf(p->errbuf, sizeof(p->errbuf),
"bad nit state %d", nh->nh_state);
1999-10-07 23:46:40 +00:00
return (-1);
}
++p->md.stat.ps_recv;
bp += ((sizeof(struct nit_hdr) + nh->nh_datalen +
sizeof(int) - 1) & ~(sizeof(int) - 1));
caplen = nh->nh_wirelen;
if (caplen > p->snapshot)
caplen = p->snapshot;
if (bpf_filter(fcode, cp, nh->nh_wirelen, caplen)) {
struct pcap_pkthdr h;
h.ts = nh->nh_timestamp;
h.len = nh->nh_wirelen;
h.caplen = caplen;
(*callback)(user, &h, cp);
if (++n >= cnt && cnt >= 0) {
p->cc = ep - bp;
p->bp = bp;
return (n);
}
}
}
p->cc = 0;
return (n);
}
static int
nit_setflags(int fd, int promisc, int to_ms, char *ebuf)
{
struct nit_ioc nioc;
2000-07-29 08:03:56 +00:00
memset(&nioc, 0, sizeof(nioc));
1999-10-07 23:46:40 +00:00
nioc.nioc_bufspace = BUFSPACE;
nioc.nioc_chunksize = CHUNKSIZE;
nioc.nioc_typetomatch = NT_ALLTYPES;
nioc.nioc_snaplen = p->snapshot;
nioc.nioc_bufalign = sizeof(int);
nioc.nioc_bufoffset = 0;
if (to_ms != 0) {
nioc.nioc_flags |= NF_TIMEOUT;
nioc.nioc_timeout.tv_sec = to_ms / 1000;
nioc.nioc_timeout.tv_usec = (to_ms * 1000) % 1000000;
}
if (promisc)
nioc.nioc_flags |= NF_PROMISC;
if (ioctl(fd, SIOCSNIT, &nioc) < 0) {
snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCSNIT: %s",
pcap_strerror(errno));
1999-10-07 23:46:40 +00:00
return (-1);
}
return (0);
}
pcap_t *
pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
{
int fd;
struct sockaddr_nit snit;
register pcap_t *p;
p = (pcap_t *)malloc(sizeof(*p));
if (p == NULL) {
strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
1999-10-07 23:46:40 +00:00
return (NULL);
}
if (snaplen < 96)
/*
* NIT requires a snapshot length of at least 96.
*/
snaplen = 96;
2000-07-29 08:03:56 +00:00
memset(p, 0, sizeof(*p));
1999-10-07 23:46:40 +00:00
p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW);
if (fd < 0) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"socket: %s", pcap_strerror(errno));
1999-10-07 23:46:40 +00:00
goto bad;
}
snit.snit_family = AF_NIT;
(void)strncpy(snit.snit_ifname, device, NITIFSIZ);
if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) {
snprintf(ebuf, PCAP_ERRBUF_SIZE,
"bind: %s: %s", snit.snit_ifname, pcap_strerror(errno));
1999-10-07 23:46:40 +00:00
goto bad;
}
p->snapshot = snaplen;
nit_setflags(p->fd, promisc, to_ms, ebuf);
/*
* NIT 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
p->linktype = PCAP_ENCAP_ETHERNET;
1999-10-07 23:46:40 +00:00
p->bufsize = BUFSPACE;
p->buffer = (u_char *)malloc(p->bufsize);
if (p->buffer == NULL) {
strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
1999-10-07 23:46:40 +00:00
goto bad;
}
return (p);
bad:
if (fd >= 0)
close(fd);
free(p);
return (NULL);
}
int
pcap_setfilter(pcap_t *p, struct bpf_program *fp)
{
p->fcode = *fp;
return (0);
}