pcap-bpf.c revision 17683
138061Smsmith/*
238061Smsmith * Copyright (c) 1993, 1994, 1995, 1996
338061Smsmith *	The Regents of the University of California.  All rights reserved.
438061Smsmith *
538061Smsmith * Redistribution and use in source and binary forms, with or without
638061Smsmith * modification, are permitted provided that: (1) source code distributions
738061Smsmith * retain the above copyright notice and this paragraph in its entirety, (2)
838061Smsmith * distributions including binary code include the above copyright notice and
938061Smsmith * this paragraph in its entirety in the documentation or other materials
1038061Smsmith * provided with the distribution, and (3) all advertising materials mentioning
1138061Smsmith * features or use of this software display the following acknowledgement:
1238061Smsmith * ``This product includes software developed by the University of California,
1338061Smsmith * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1438061Smsmith * the University nor the names of its contributors may be used to endorse
1538061Smsmith * or promote products derived from this software without specific prior
1638061Smsmith * written permission.
1738061Smsmith * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1838061Smsmith * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1938061Smsmith * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2038061Smsmith */
2138061Smsmith#ifndef lint
2238061Smsmithstatic  char rcsid[] =
2338061Smsmith    "@(#)$Header: pcap-bpf.c,v 1.26 96/07/15 00:48:50 leres Exp $ (LBL)";
2438061Smsmith#endif
2538061Smsmith
2645342Speter#include <sys/param.h>			/* optionally get BSD define */
2738061Smsmith#include <sys/time.h>
2838061Smsmith#include <sys/timeb.h>
2938061Smsmith#include <sys/socket.h>
3038061Smsmith#include <sys/file.h>
3138061Smsmith#include <sys/ioctl.h>
3238061Smsmith
3338061Smsmith#include <net/if.h>
3438061Smsmith
3538061Smsmith#include <ctype.h>
3638061Smsmith#include <errno.h>
3738061Smsmith#include <netdb.h>
3838061Smsmith#include <stdio.h>
3938061Smsmith#include <stdlib.h>
4038061Smsmith#include <string.h>
4138061Smsmith#include <unistd.h>
4238061Smsmith
4338061Smsmith#include "pcap-int.h"
4442475Snsouch
4542475Snsouch#include "gnuc.h"
4638061Smsmith#ifdef HAVE_OS_PROTO_H
4738061Smsmith#include "os-proto.h"
4838061Smsmith#endif
4938061Smsmith
5038061Smsmithint
5138061Smsmithpcap_stats(pcap_t *p, struct pcap_stat *ps)
5238061Smsmith{
5338061Smsmith	struct bpf_stat s;
5438061Smsmith
5538061Smsmith	if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) {
5638061Smsmith		sprintf(p->errbuf, "BIOCGSTATS: %s", pcap_strerror(errno));
5738061Smsmith		return (-1);
5838061Smsmith	}
5938061Smsmith
6038061Smsmith	ps->ps_recv = s.bs_recv;
6138061Smsmith	ps->ps_drop = s.bs_drop;
6238061Smsmith	return (0);
6338061Smsmith}
6438061Smsmith
6538061Smsmithint
6638061Smsmithpcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
6738061Smsmith{
6838061Smsmith	int cc;
6938061Smsmith	int n = 0;
7038061Smsmith	register u_char *bp, *ep;
7138061Smsmith
7238061Smsmith again:
7338061Smsmith	cc = p->cc;
7438061Smsmith	if (p->cc == 0) {
7538061Smsmith		cc = read(p->fd, (char *)p->buffer, p->bufsize);
7638061Smsmith		if (cc < 0) {
7738061Smsmith			/* Don't choke when we get ptraced */
7838061Smsmith			switch (errno) {
7938061Smsmith
8038061Smsmith			case EINTR:
8138061Smsmith				goto again;
8239134Snsouch
8339134Snsouch			case EWOULDBLOCK:
8438061Smsmith				return (0);
8538061Smsmith#if defined(sun) && !defined(BSD)
8638061Smsmith			/*
8738061Smsmith			 * Due to a SunOS bug, after 2^31 bytes, the kernel
8838061Smsmith			 * file offset overflows and read fails with EINVAL.
8938061Smsmith			 * The lseek() to 0 will fix things.
9038061Smsmith			 */
9138061Smsmith			case EINVAL:
9238061Smsmith				if (lseek(p->fd, 0L, SEEK_CUR) +
9338061Smsmith				    p->bufsize < 0) {
9438061Smsmith					(void)lseek(p->fd, 0L, SEEK_SET);
9538061Smsmith					goto again;
9638061Smsmith				}
9739134Snsouch				/* fall through */
9839134Snsouch#endif
9939134Snsouch			}
10039134Snsouch			sprintf(p->errbuf, "read: %s", pcap_strerror(errno));
10145342Speter			return (-1);
10239134Snsouch		}
10345342Speter		bp = p->buffer;
10439134Snsouch	} else
10539134Snsouch		bp = p->bp;
10639134Snsouch
10739134Snsouch	/*
10839134Snsouch	 * Loop through each packet.
10938061Smsmith	 */
11038061Smsmith#define bhp ((struct bpf_hdr *)bp)
11138061Smsmith	ep = bp + cc;
11238061Smsmith	while (bp < ep) {
11338061Smsmith		register int caplen, hdrlen;
11438061Smsmith		caplen = bhp->bh_caplen;
11538061Smsmith		hdrlen = bhp->bh_hdrlen;
11639134Snsouch		/*
11739134Snsouch		 * XXX A bpf_hdr matches a pcap_pkthdr.
11838061Smsmith		 */
11938061Smsmith		(*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen);
12038061Smsmith		bp += BPF_WORDALIGN(caplen + hdrlen);
12138061Smsmith		if (++n >= cnt && cnt > 0) {
12238061Smsmith			p->bp = bp;
12338061Smsmith			p->cc = ep - bp;
12438061Smsmith			return (n);
12539134Snsouch		}
12638061Smsmith	}
12738061Smsmith#undef bhp
12838061Smsmith	p->cc = 0;
12938061Smsmith	return (n);
13039134Snsouch}
13138061Smsmith
13238061Smsmithstatic inline int
13338061Smsmithbpf_open(pcap_t *p, char *errbuf)
13438061Smsmith{
13539134Snsouch	int fd;
13638061Smsmith	int n = 0;
13738061Smsmith	char device[sizeof "/dev/bpf000"];
13838061Smsmith
13938061Smsmith	/*
14038061Smsmith	 * Go through all the minors and find one that isn't in use.
14138061Smsmith	 */
14238061Smsmith	do {
14338061Smsmith		(void)sprintf(device, "/dev/bpf%d", n++);
14438061Smsmith		fd = open(device, O_RDONLY);
14538061Smsmith	} while (fd < 0 && errno == EBUSY);
14638061Smsmith
14738061Smsmith	/*
14838061Smsmith	 * XXX better message for all minors used
14938061Smsmith	 */
15038061Smsmith	if (fd < 0)
15138061Smsmith		sprintf(errbuf, "%s: %s", device, pcap_strerror(errno));
15238061Smsmith
15338061Smsmith	return (fd);
15438061Smsmith}
15538061Smsmith
15638061Smsmithpcap_t *
15738061Smsmithpcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
15838061Smsmith{
15939134Snsouch	int fd;
16039134Snsouch	struct ifreq ifr;
16138061Smsmith	struct bpf_version bv;
16238061Smsmith	u_int v;
16338061Smsmith	pcap_t *p;
16438061Smsmith
16538061Smsmith	p = (pcap_t *)malloc(sizeof(*p));
16638061Smsmith	if (p == NULL) {
16738061Smsmith		sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
16838061Smsmith		return (NULL);
16938061Smsmith	}
17038061Smsmith	bzero(p, sizeof(*p));
17138061Smsmith	fd = bpf_open(p, ebuf);
17238061Smsmith	if (fd < 0)
17338061Smsmith		goto bad;
17438061Smsmith
17538061Smsmith	p->fd = fd;
17638061Smsmith	p->snapshot = snaplen;
17738061Smsmith
17839134Snsouch	if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
17938061Smsmith		sprintf(ebuf, "BIOCVERSION: %s", pcap_strerror(errno));
18038061Smsmith		goto bad;
18138061Smsmith	}
18238061Smsmith	if (bv.bv_major != BPF_MAJOR_VERSION ||
18338061Smsmith	    bv.bv_minor < BPF_MINOR_VERSION) {
18438061Smsmith		sprintf(ebuf, "kernel bpf filter out of date");
18538061Smsmith		goto bad;
18638061Smsmith	}
18738061Smsmith	(void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
18838061Smsmith	if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
18943433Snsouch		sprintf(ebuf, "%s: %s", device, pcap_strerror(errno));
19038061Smsmith		goto bad;
19138061Smsmith	}
19238061Smsmith	/* Get the data link layer type. */
19338061Smsmith	if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
19438061Smsmith		sprintf(ebuf, "BIOCGDLT: %s", pcap_strerror(errno));
19538061Smsmith		goto bad;
19638061Smsmith	}
19738061Smsmith	p->linktype = v;
19839134Snsouch
19938061Smsmith	/* set timeout */
20038061Smsmith	if (to_ms != 0) {
20138061Smsmith		struct timeval to;
20238061Smsmith		to.tv_sec = to_ms / 1000;
20338061Smsmith		to.tv_usec = (to_ms * 1000) % 1000000;
20438061Smsmith		if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
20543433Snsouch			sprintf(ebuf, "BIOCSRTIMEOUT: %s",
20638061Smsmith				pcap_strerror(errno));
20738061Smsmith			goto bad;
20838061Smsmith		}
20938061Smsmith	}
21038061Smsmith	if (promisc)
21138061Smsmith		/* set promiscuous mode, okay if it fails */
21238061Smsmith		(void)ioctl(p->fd, BIOCPROMISC, NULL);
21338061Smsmith
21439134Snsouch	if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
21538061Smsmith		sprintf(ebuf, "BIOCGBLEN: %s", pcap_strerror(errno));
21638061Smsmith		goto bad;
21738061Smsmith	}
21838061Smsmith	p->bufsize = v;
21938061Smsmith	p->buffer = (u_char *)malloc(p->bufsize);
22038061Smsmith	if (p->buffer == NULL) {
22143433Snsouch		sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
22238061Smsmith		goto bad;
22338061Smsmith	}
22438061Smsmith
22538061Smsmith	return (p);
22638061Smsmith bad:
22738061Smsmith	(void)close(fd);
22839134Snsouch	free(p);
22938061Smsmith	return (NULL);
23038061Smsmith}
23138061Smsmith
23243433Snsouchint
23343433Snsouchpcap_setfilter(pcap_t *p, struct bpf_program *fp)
23443433Snsouch{
23538061Smsmith	if (p->sf.rfile != NULL)
23638061Smsmith		p->fcode = *fp;
23738061Smsmith	else if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) {
23838061Smsmith		sprintf(p->errbuf, "BIOCSETF: %s", pcap_strerror(errno));
23938061Smsmith		return (-1);
24038061Smsmith	}
24138061Smsmith	return (0);
24238061Smsmith}
24339134Snsouch