aboutsummaryrefslogtreecommitdiff
path: root/contrib/libpcap/pcap-pf.c
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2005-05-29 17:46:52 +0000
committerSam Leffler <sam@FreeBSD.org>2005-05-29 17:46:52 +0000
commit04fb274578a5def82f89c3a522b3f28c8916aa1f (patch)
treeb733a54335042f876f8969020dc9dc4408f485f4 /contrib/libpcap/pcap-pf.c
parentfeb4ecdbac00a57548c3e75b168107e9c470f354 (diff)
downloadsrc-04fb274578a5def82f89c3a522b3f28c8916aa1f.tar.gz
src-04fb274578a5def82f89c3a522b3f28c8916aa1f.zip
Virgin import of libpcap v0.9.1 (alpha 096) from tcpdump.org
Notes
Notes: svn path=/vendor/libpcap/dist/; revision=146768
Diffstat (limited to 'contrib/libpcap/pcap-pf.c')
-rw-r--r--contrib/libpcap/pcap-pf.c115
1 files changed, 93 insertions, 22 deletions
diff --git a/contrib/libpcap/pcap-pf.c b/contrib/libpcap/pcap-pf.c
index e84d1c7db1b7..1c3158aeba39 100644
--- a/contrib/libpcap/pcap-pf.c
+++ b/contrib/libpcap/pcap-pf.c
@@ -24,7 +24,7 @@
#ifndef lint
static const char rcsid[] _U_ =
- "@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.79.2.5 2003/11/22 00:32:55 guy Exp $ (LBL)";
+ "@(#) $Header: /tcpdump/master/libpcap/pcap-pf.c,v 1.91 2005/02/26 21:58:06 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
@@ -129,10 +129,7 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
*/
n = 0;
#ifdef PCAP_FDDIPAD
- if (pc->linktype == DLT_FDDI)
- pad = pcap_fddipad;
- else
- pad = 0;
+ pad = p->fddipad;
#endif
while (cc > 0) {
/*
@@ -182,10 +179,6 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
inc = ENALIGN(buflen + sp->ens_stamplen);
cc -= inc;
bp += inc;
-#ifdef PCAP_FDDIPAD
- p += pad;
- buflen -= pad;
-#endif
pc->md.TotPkts++;
pc->md.TotDrops += sp->ens_dropped;
pc->md.TotMissed = sp->ens_ifoverflows;
@@ -195,6 +188,14 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
/*
* Short-circuit evaluation: if using BPF filter
* in kernel, no need to do it now.
+ *
+#ifdef PCAP_FDDIPAD
+ * Note: the filter code was generated assuming
+ * that p->fddipad was the amount of padding
+ * before the header, as that's what's required
+ * in the kernel, so we run the filter before
+ * skipping that padding.
+#endif
*/
if (fcode == NULL ||
bpf_filter(fcode, p, sp->ens_count, buflen)) {
@@ -206,6 +207,10 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
#else
h.len = sp->ens_count;
#endif
+#ifdef PCAP_FDDIPAD
+ p += pad;
+ buflen -= pad;
+#endif
h.caplen = buflen;
(*callback)(user, &h, p);
if (++n >= cnt && cnt > 0) {
@@ -220,6 +225,20 @@ pcap_read_pf(pcap_t *pc, int cnt, pcap_handler callback, u_char *user)
}
static int
+pcap_inject_pf(pcap_t *p, const void *buf, size_t size)
+{
+ int ret;
+
+ ret = write(p->fd, buf, size);
+ if (ret == -1) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
+ pcap_strerror(errno));
+ return (-1);
+ }
+ return (ret);
+}
+
+static int
pcap_stats_pf(pcap_t *p, struct pcap_stat *ps)
{
@@ -265,14 +284,13 @@ pcap_stats_pf(pcap_t *p, struct pcap_stat *ps)
return (0);
}
-static void
-pcap_close_pf(pcap_t *p)
-{
- if (p->buffer != NULL)
- free(p->buffer);
- if (p->fd >= 0)
- close(p->fd);
-}
+/*
+ * We include the OS's <net/bpf.h>, not our "pcap-bpf.h", so we probably
+ * don't get DLT_DOCSIS defined.
+ */
+#ifndef DLT_DOCSIS
+#define DLT_DOCSIS 143
+#endif
pcap_t *
pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
@@ -291,14 +309,28 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
return (0);
}
memset(p, 0, sizeof(*p));
-
/*
+ * Initially try a read/write open (to allow the inject
+ * method to work). If that fails due to permission
+ * issues, fall back to read-only. This allows a
+ * non-root user to be granted specific access to pcap
+ * capabilities via file permissions.
+ *
+ * XXX - we should have an API that has a flag that
+ * controls whether to open read-only or read-write,
+ * so that denial of permission to send (or inability
+ * to send, if sending packets isn't supported on
+ * the device in question) can be indicated at open
+ * time.
+ *
* XXX - we assume here that "pfopen()" does not, in fact, modify
* its argument, even though it takes a "char *" rather than a
* "const char *" as its first argument. That appears to be
* the case, at least on Digital UNIX 4.0.
*/
- p->fd = pfopen(device, O_RDONLY);
+ p->fd = pfopen(device, O_RDWR);
+ if (p->fd == -1 && errno == EACCES)
+ p->fd = pfopen(device, O_RDONLY);
if (p->fd < 0) {
snprintf(ebuf, PCAP_ERRBUF_SIZE, "pf open: %s: %s\n\
your system may not be properly configured; see the packetfilter(4) man page\n",
@@ -340,6 +372,25 @@ your system may not be properly configured; see the packetfilter(4) man page\n",
case ENDT_10MB:
p->linktype = DLT_EN10MB;
p->offset = 2;
+ /*
+ * This is (presumably) a real Ethernet capture; give it a
+ * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
+ * that an application can let you choose it, in case you're
+ * capturing DOCSIS traffic that a Cisco Cable Modem
+ * Termination System is putting out onto an Ethernet (it
+ * doesn't put an Ethernet header onto the wire, it puts raw
+ * DOCSIS frames out on the wire inside the low-level
+ * Ethernet framing).
+ */
+ p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
+ /*
+ * If that fails, just leave the list empty.
+ */
+ if (p->dlt_list != NULL) {
+ p->dlt_list[0] = DLT_EN10MB;
+ p->dlt_list[1] = DLT_DOCSIS;
+ p->dlt_count = 2;
+ }
break;
case ENDT_FDDI:
@@ -396,9 +447,13 @@ your system may not be properly configured; see the packetfilter(4) man page\n",
}
/* set truncation */
#ifdef PCAP_FDDIPAD
- if (p->linktype == DLT_FDDI)
+ if (p->linktype == DLT_FDDI) {
+ p->fddipad = PCAP_FDDIPAD:
+
/* packetfilter includes the padding in the snapshot */
- snaplen += pcap_fddipad;
+ snaplen += PCAP_FDDIPAD;
+ } else
+ p->fddipad = 0;
#endif
if (ioctl(p->fd, EIOCTRUNCATE, (caddr_t)&snaplen) < 0) {
snprintf(ebuf, PCAP_ERRBUF_SIZE, "EIOCTRUNCATE: %s",
@@ -440,17 +495,23 @@ your system may not be properly configured; see the packetfilter(4) man page\n",
p->selectable_fd = p->fd;
p->read_op = pcap_read_pf;
+ p->inject_op = pcap_inject_pf;
p->setfilter_op = pcap_setfilter_pf;
p->set_datalink_op = NULL; /* can't change data link type */
p->getnonblock_op = pcap_getnonblock_fd;
p->setnonblock_op = pcap_setnonblock_fd;
p->stats_op = pcap_stats_pf;
- p->close_op = pcap_close_pf;
+ p->close_op = pcap_close_common;
return (p);
bad:
if (p->fd >= 0)
close(p->fd);
+ /*
+ * Get rid of any link-layer type list we allocated.
+ */
+ if (p->dlt_list != NULL)
+ free(p->dlt_list);
free(p);
return (NULL);
}
@@ -506,6 +567,16 @@ pcap_setfilter_pf(pcap_t *p, struct bpf_program *fp)
*/
fprintf(stderr, "tcpdump: Using kernel BPF filter\n");
p->md.use_bpf = 1;
+
+ /*
+ * Discard any previously-received packets,
+ * as they might have passed whatever filter
+ * was formerly in effect, but might not pass
+ * this filter (BIOCSETF discards packets buffered
+ * in the kernel, so you can lose packets in any
+ * case).
+ */
+ p->cc = 0;
return (0);
}