pcap-bpf.c revision 39291
117683Spst/*
239291Sfenner * Copyright (c) 1993, 1994, 1995, 1996, 1998
317683Spst *	The Regents of the University of California.  All rights reserved.
417683Spst *
517683Spst * Redistribution and use in source and binary forms, with or without
617683Spst * modification, are permitted provided that: (1) source code distributions
717683Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817683Spst * distributions including binary code include the above copyright notice and
917683Spst * this paragraph in its entirety in the documentation or other materials
1017683Spst * provided with the distribution, and (3) all advertising materials mentioning
1117683Spst * features or use of this software display the following acknowledgement:
1217683Spst * ``This product includes software developed by the University of California,
1317683Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417683Spst * the University nor the names of its contributors may be used to endorse
1517683Spst * or promote products derived from this software without specific prior
1617683Spst * written permission.
1717683Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817683Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917683Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017683Spst */
2117683Spst#ifndef lint
2226175Sfennerstatic const char rcsid[] =
2339291Sfenner    "@(#) $Header: pcap-bpf.c,v 1.31 98/07/12 13:14:55 leres Exp $ (LBL)";
2417683Spst#endif
2517683Spst
2617683Spst#include <sys/param.h>			/* optionally get BSD define */
2717683Spst#include <sys/time.h>
2817683Spst#include <sys/timeb.h>
2917683Spst#include <sys/socket.h>
3017683Spst#include <sys/file.h>
3117683Spst#include <sys/ioctl.h>
3217683Spst
3317683Spst#include <net/if.h>
3417683Spst
3517683Spst#include <ctype.h>
3617683Spst#include <errno.h>
3717683Spst#include <netdb.h>
3817683Spst#include <stdio.h>
3917683Spst#include <stdlib.h>
4017683Spst#include <string.h>
4117683Spst#include <unistd.h>
4217683Spst
4317683Spst#include "pcap-int.h"
4417683Spst
4517683Spst#include "gnuc.h"
4617683Spst#ifdef HAVE_OS_PROTO_H
4717683Spst#include "os-proto.h"
4817683Spst#endif
4917683Spst
5017683Spstint
5117683Spstpcap_stats(pcap_t *p, struct pcap_stat *ps)
5217683Spst{
5317683Spst	struct bpf_stat s;
5417683Spst
5517683Spst	if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) {
5617683Spst		sprintf(p->errbuf, "BIOCGSTATS: %s", pcap_strerror(errno));
5717683Spst		return (-1);
5817683Spst	}
5917683Spst
6017683Spst	ps->ps_recv = s.bs_recv;
6117683Spst	ps->ps_drop = s.bs_drop;
6217683Spst	return (0);
6317683Spst}
6417683Spst
6517683Spstint
6617683Spstpcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
6717683Spst{
6817683Spst	int cc;
6917683Spst	int n = 0;
7017683Spst	register u_char *bp, *ep;
7117683Spst
7217683Spst again:
7317683Spst	cc = p->cc;
7417683Spst	if (p->cc == 0) {
7517683Spst		cc = read(p->fd, (char *)p->buffer, p->bufsize);
7617683Spst		if (cc < 0) {
7717683Spst			/* Don't choke when we get ptraced */
7817683Spst			switch (errno) {
7917683Spst
8017683Spst			case EINTR:
8117683Spst				goto again;
8217683Spst
8317683Spst			case EWOULDBLOCK:
8417683Spst				return (0);
8517683Spst#if defined(sun) && !defined(BSD)
8617683Spst			/*
8717683Spst			 * Due to a SunOS bug, after 2^31 bytes, the kernel
8817683Spst			 * file offset overflows and read fails with EINVAL.
8917683Spst			 * The lseek() to 0 will fix things.
9017683Spst			 */
9117683Spst			case EINVAL:
9217683Spst				if (lseek(p->fd, 0L, SEEK_CUR) +
9317683Spst				    p->bufsize < 0) {
9417683Spst					(void)lseek(p->fd, 0L, SEEK_SET);
9517683Spst					goto again;
9617683Spst				}
9717683Spst				/* fall through */
9817683Spst#endif
9917683Spst			}
10017683Spst			sprintf(p->errbuf, "read: %s", pcap_strerror(errno));
10117683Spst			return (-1);
10217683Spst		}
10317683Spst		bp = p->buffer;
10417683Spst	} else
10517683Spst		bp = p->bp;
10617683Spst
10717683Spst	/*
10817683Spst	 * Loop through each packet.
10917683Spst	 */
11017683Spst#define bhp ((struct bpf_hdr *)bp)
11117683Spst	ep = bp + cc;
11217683Spst	while (bp < ep) {
11317683Spst		register int caplen, hdrlen;
11417683Spst		caplen = bhp->bh_caplen;
11517683Spst		hdrlen = bhp->bh_hdrlen;
11617683Spst		/*
11717683Spst		 * XXX A bpf_hdr matches a pcap_pkthdr.
11817683Spst		 */
11917683Spst		(*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen);
12017683Spst		bp += BPF_WORDALIGN(caplen + hdrlen);
12117683Spst		if (++n >= cnt && cnt > 0) {
12217683Spst			p->bp = bp;
12317683Spst			p->cc = ep - bp;
12417683Spst			return (n);
12517683Spst		}
12617683Spst	}
12717683Spst#undef bhp
12817683Spst	p->cc = 0;
12917683Spst	return (n);
13017683Spst}
13117683Spst
13217683Spststatic inline int
13317683Spstbpf_open(pcap_t *p, char *errbuf)
13417683Spst{
13517683Spst	int fd;
13617683Spst	int n = 0;
13717683Spst	char device[sizeof "/dev/bpf000"];
13817683Spst
13917683Spst	/*
14017683Spst	 * Go through all the minors and find one that isn't in use.
14117683Spst	 */
14217683Spst	do {
14317683Spst		(void)sprintf(device, "/dev/bpf%d", n++);
14417683Spst		fd = open(device, O_RDONLY);
14517683Spst	} while (fd < 0 && errno == EBUSY);
14617683Spst
14717683Spst	/*
14817683Spst	 * XXX better message for all minors used
14917683Spst	 */
15017683Spst	if (fd < 0)
15117683Spst		sprintf(errbuf, "%s: %s", device, pcap_strerror(errno));
15217683Spst
15317683Spst	return (fd);
15417683Spst}
15517683Spst
15617683Spstpcap_t *
15717683Spstpcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
15817683Spst{
15917683Spst	int fd;
16017683Spst	struct ifreq ifr;
16117683Spst	struct bpf_version bv;
16217683Spst	u_int v;
16317683Spst	pcap_t *p;
16417683Spst
16517683Spst	p = (pcap_t *)malloc(sizeof(*p));
16617683Spst	if (p == NULL) {
16717683Spst		sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
16817683Spst		return (NULL);
16917683Spst	}
17017683Spst	bzero(p, sizeof(*p));
17117683Spst	fd = bpf_open(p, ebuf);
17217683Spst	if (fd < 0)
17317683Spst		goto bad;
17417683Spst
17517683Spst	p->fd = fd;
17617683Spst	p->snapshot = snaplen;
17717683Spst
17817683Spst	if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
17917683Spst		sprintf(ebuf, "BIOCVERSION: %s", pcap_strerror(errno));
18017683Spst		goto bad;
18117683Spst	}
18217683Spst	if (bv.bv_major != BPF_MAJOR_VERSION ||
18317683Spst	    bv.bv_minor < BPF_MINOR_VERSION) {
18417683Spst		sprintf(ebuf, "kernel bpf filter out of date");
18517683Spst		goto bad;
18617683Spst	}
18739291Sfenner	v = 32768;	/* XXX this should be a user-accessible hook */
18839291Sfenner	/* Ignore the return value - this is because the call fails on
18939291Sfenner	 * BPF systems that don't have kernel malloc.  And if the call
19039291Sfenner	 * fails, it's no big deal, we just continue to use the standard
19139291Sfenner	 * buffer size.
19239291Sfenner	 */
19339291Sfenner	(void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
19439291Sfenner
19517683Spst	(void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
19617683Spst	if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
19717683Spst		sprintf(ebuf, "%s: %s", device, pcap_strerror(errno));
19817683Spst		goto bad;
19917683Spst	}
20017683Spst	/* Get the data link layer type. */
20117683Spst	if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
20217683Spst		sprintf(ebuf, "BIOCGDLT: %s", pcap_strerror(errno));
20317683Spst		goto bad;
20417683Spst	}
20539291Sfenner#if _BSDI_VERSION - 0 >= 199510
20639291Sfenner	/* The SLIP and PPP link layer header changed in BSD/OS 2.1 */
20739291Sfenner	switch (v) {
20839291Sfenner
20939291Sfenner	case DLT_SLIP:
21039291Sfenner		v = DLT_SLIP_BSDOS;
21139291Sfenner		break;
21239291Sfenner
21339291Sfenner	case DLT_PPP:
21439291Sfenner		v = DLT_PPP_BSDOS;
21539291Sfenner		break;
21639291Sfenner	}
21739291Sfenner#endif
21817683Spst	p->linktype = v;
21917683Spst
22017683Spst	/* set timeout */
22117683Spst	if (to_ms != 0) {
22217683Spst		struct timeval to;
22317683Spst		to.tv_sec = to_ms / 1000;
22417683Spst		to.tv_usec = (to_ms * 1000) % 1000000;
22517683Spst		if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
22617683Spst			sprintf(ebuf, "BIOCSRTIMEOUT: %s",
22717683Spst				pcap_strerror(errno));
22817683Spst			goto bad;
22917683Spst		}
23017683Spst	}
23117683Spst	if (promisc)
23217683Spst		/* set promiscuous mode, okay if it fails */
23317683Spst		(void)ioctl(p->fd, BIOCPROMISC, NULL);
23417683Spst
23517683Spst	if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
23617683Spst		sprintf(ebuf, "BIOCGBLEN: %s", pcap_strerror(errno));
23717683Spst		goto bad;
23817683Spst	}
23917683Spst	p->bufsize = v;
24017683Spst	p->buffer = (u_char *)malloc(p->bufsize);
24117683Spst	if (p->buffer == NULL) {
24217683Spst		sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
24317683Spst		goto bad;
24417683Spst	}
24517683Spst
24617683Spst	return (p);
24717683Spst bad:
24817683Spst	(void)close(fd);
24917683Spst	free(p);
25017683Spst	return (NULL);
25117683Spst}
25217683Spst
25317683Spstint
25417683Spstpcap_setfilter(pcap_t *p, struct bpf_program *fp)
25517683Spst{
25617683Spst	if (p->sf.rfile != NULL)
25717683Spst		p->fcode = *fp;
25817683Spst	else if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) {
25917683Spst		sprintf(p->errbuf, "BIOCSETF: %s", pcap_strerror(errno));
26017683Spst		return (-1);
26117683Spst	}
26217683Spst	return (0);
26317683Spst}
264