xref: /freebsd/contrib/libpcap/pcap-bpf.c (revision 8751327cb402b224f87d580cfa2cb02b1467e9c0)
18cf6c252SPaul Traina /*
2a4b5b39fSBill Fenner  * Copyright (c) 1993, 1994, 1995, 1996, 1998
38cf6c252SPaul Traina  *	The Regents of the University of California.  All rights reserved.
48cf6c252SPaul Traina  *
58cf6c252SPaul Traina  * Redistribution and use in source and binary forms, with or without
68cf6c252SPaul Traina  * modification, are permitted provided that: (1) source code distributions
78cf6c252SPaul Traina  * retain the above copyright notice and this paragraph in its entirety, (2)
88cf6c252SPaul Traina  * distributions including binary code include the above copyright notice and
98cf6c252SPaul Traina  * this paragraph in its entirety in the documentation or other materials
108cf6c252SPaul Traina  * provided with the distribution, and (3) all advertising materials mentioning
118cf6c252SPaul Traina  * features or use of this software display the following acknowledgement:
128cf6c252SPaul Traina  * ``This product includes software developed by the University of California,
138cf6c252SPaul Traina  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
148cf6c252SPaul Traina  * the University nor the names of its contributors may be used to endorse
158cf6c252SPaul Traina  * or promote products derived from this software without specific prior
168cf6c252SPaul Traina  * written permission.
178cf6c252SPaul Traina  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
188cf6c252SPaul Traina  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
198cf6c252SPaul Traina  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
208cf6c252SPaul Traina  */
218cf6c252SPaul Traina #ifndef lint
223052b236SBill Fenner static const char rcsid[] =
238751327cSBill Fenner     "@(#) $Header: /tcpdump/master/libpcap/pcap-bpf.c,v 1.32 1999/10/19 15:18:30 itojun Exp $ (LBL)";
248cf6c252SPaul Traina #endif
258cf6c252SPaul Traina 
268cf6c252SPaul Traina #include <sys/param.h>			/* optionally get BSD define */
278cf6c252SPaul Traina #include <sys/time.h>
288cf6c252SPaul Traina #include <sys/timeb.h>
298cf6c252SPaul Traina #include <sys/socket.h>
308cf6c252SPaul Traina #include <sys/file.h>
318cf6c252SPaul Traina #include <sys/ioctl.h>
328cf6c252SPaul Traina 
338cf6c252SPaul Traina #include <net/if.h>
348cf6c252SPaul Traina 
358cf6c252SPaul Traina #include <ctype.h>
368cf6c252SPaul Traina #include <errno.h>
378cf6c252SPaul Traina #include <netdb.h>
388cf6c252SPaul Traina #include <stdio.h>
398cf6c252SPaul Traina #include <stdlib.h>
408cf6c252SPaul Traina #include <string.h>
418cf6c252SPaul Traina #include <unistd.h>
428cf6c252SPaul Traina 
438cf6c252SPaul Traina #include "pcap-int.h"
448cf6c252SPaul Traina 
458cf6c252SPaul Traina #include "gnuc.h"
468cf6c252SPaul Traina #ifdef HAVE_OS_PROTO_H
478cf6c252SPaul Traina #include "os-proto.h"
488cf6c252SPaul Traina #endif
498cf6c252SPaul Traina 
508751327cSBill Fenner #include "gencode.h"
518751327cSBill Fenner 
528cf6c252SPaul Traina int
538cf6c252SPaul Traina pcap_stats(pcap_t *p, struct pcap_stat *ps)
548cf6c252SPaul Traina {
558cf6c252SPaul Traina 	struct bpf_stat s;
568cf6c252SPaul Traina 
578cf6c252SPaul Traina 	if (ioctl(p->fd, BIOCGSTATS, (caddr_t)&s) < 0) {
588cf6c252SPaul Traina 		sprintf(p->errbuf, "BIOCGSTATS: %s", pcap_strerror(errno));
598cf6c252SPaul Traina 		return (-1);
608cf6c252SPaul Traina 	}
618cf6c252SPaul Traina 
628cf6c252SPaul Traina 	ps->ps_recv = s.bs_recv;
638cf6c252SPaul Traina 	ps->ps_drop = s.bs_drop;
648cf6c252SPaul Traina 	return (0);
658cf6c252SPaul Traina }
668cf6c252SPaul Traina 
678cf6c252SPaul Traina int
688cf6c252SPaul Traina pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
698cf6c252SPaul Traina {
708cf6c252SPaul Traina 	int cc;
718cf6c252SPaul Traina 	int n = 0;
728cf6c252SPaul Traina 	register u_char *bp, *ep;
738cf6c252SPaul Traina 
748cf6c252SPaul Traina  again:
758cf6c252SPaul Traina 	cc = p->cc;
768cf6c252SPaul Traina 	if (p->cc == 0) {
778cf6c252SPaul Traina 		cc = read(p->fd, (char *)p->buffer, p->bufsize);
788cf6c252SPaul Traina 		if (cc < 0) {
798cf6c252SPaul Traina 			/* Don't choke when we get ptraced */
808cf6c252SPaul Traina 			switch (errno) {
818cf6c252SPaul Traina 
828cf6c252SPaul Traina 			case EINTR:
838cf6c252SPaul Traina 				goto again;
848cf6c252SPaul Traina 
858cf6c252SPaul Traina 			case EWOULDBLOCK:
868cf6c252SPaul Traina 				return (0);
878cf6c252SPaul Traina #if defined(sun) && !defined(BSD)
888cf6c252SPaul Traina 			/*
898cf6c252SPaul Traina 			 * Due to a SunOS bug, after 2^31 bytes, the kernel
908cf6c252SPaul Traina 			 * file offset overflows and read fails with EINVAL.
918cf6c252SPaul Traina 			 * The lseek() to 0 will fix things.
928cf6c252SPaul Traina 			 */
938cf6c252SPaul Traina 			case EINVAL:
948cf6c252SPaul Traina 				if (lseek(p->fd, 0L, SEEK_CUR) +
958cf6c252SPaul Traina 				    p->bufsize < 0) {
968cf6c252SPaul Traina 					(void)lseek(p->fd, 0L, SEEK_SET);
978cf6c252SPaul Traina 					goto again;
988cf6c252SPaul Traina 				}
998cf6c252SPaul Traina 				/* fall through */
1008cf6c252SPaul Traina #endif
1018cf6c252SPaul Traina 			}
1028cf6c252SPaul Traina 			sprintf(p->errbuf, "read: %s", pcap_strerror(errno));
1038cf6c252SPaul Traina 			return (-1);
1048cf6c252SPaul Traina 		}
1058cf6c252SPaul Traina 		bp = p->buffer;
1068cf6c252SPaul Traina 	} else
1078cf6c252SPaul Traina 		bp = p->bp;
1088cf6c252SPaul Traina 
1098cf6c252SPaul Traina 	/*
1108cf6c252SPaul Traina 	 * Loop through each packet.
1118cf6c252SPaul Traina 	 */
1128cf6c252SPaul Traina #define bhp ((struct bpf_hdr *)bp)
1138cf6c252SPaul Traina 	ep = bp + cc;
1148cf6c252SPaul Traina 	while (bp < ep) {
1158cf6c252SPaul Traina 		register int caplen, hdrlen;
1168cf6c252SPaul Traina 		caplen = bhp->bh_caplen;
1178cf6c252SPaul Traina 		hdrlen = bhp->bh_hdrlen;
1188cf6c252SPaul Traina 		/*
1198cf6c252SPaul Traina 		 * XXX A bpf_hdr matches a pcap_pkthdr.
1208cf6c252SPaul Traina 		 */
1218cf6c252SPaul Traina 		(*callback)(user, (struct pcap_pkthdr*)bp, bp + hdrlen);
1228cf6c252SPaul Traina 		bp += BPF_WORDALIGN(caplen + hdrlen);
1238cf6c252SPaul Traina 		if (++n >= cnt && cnt > 0) {
1248cf6c252SPaul Traina 			p->bp = bp;
1258cf6c252SPaul Traina 			p->cc = ep - bp;
1268cf6c252SPaul Traina 			return (n);
1278cf6c252SPaul Traina 		}
1288cf6c252SPaul Traina 	}
1298cf6c252SPaul Traina #undef bhp
1308cf6c252SPaul Traina 	p->cc = 0;
1318cf6c252SPaul Traina 	return (n);
1328cf6c252SPaul Traina }
1338cf6c252SPaul Traina 
1348cf6c252SPaul Traina static inline int
1358cf6c252SPaul Traina bpf_open(pcap_t *p, char *errbuf)
1368cf6c252SPaul Traina {
1378cf6c252SPaul Traina 	int fd;
1388cf6c252SPaul Traina 	int n = 0;
1398cf6c252SPaul Traina 	char device[sizeof "/dev/bpf000"];
1408cf6c252SPaul Traina 
1418cf6c252SPaul Traina 	/*
1428cf6c252SPaul Traina 	 * Go through all the minors and find one that isn't in use.
1438cf6c252SPaul Traina 	 */
1448cf6c252SPaul Traina 	do {
1458cf6c252SPaul Traina 		(void)sprintf(device, "/dev/bpf%d", n++);
1468cf6c252SPaul Traina 		fd = open(device, O_RDONLY);
1478cf6c252SPaul Traina 	} while (fd < 0 && errno == EBUSY);
1488cf6c252SPaul Traina 
1498cf6c252SPaul Traina 	/*
1508cf6c252SPaul Traina 	 * XXX better message for all minors used
1518cf6c252SPaul Traina 	 */
1528cf6c252SPaul Traina 	if (fd < 0)
1538cf6c252SPaul Traina 		sprintf(errbuf, "%s: %s", device, pcap_strerror(errno));
1548cf6c252SPaul Traina 
1558cf6c252SPaul Traina 	return (fd);
1568cf6c252SPaul Traina }
1578cf6c252SPaul Traina 
1588cf6c252SPaul Traina pcap_t *
1598cf6c252SPaul Traina pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
1608cf6c252SPaul Traina {
1618cf6c252SPaul Traina 	int fd;
1628cf6c252SPaul Traina 	struct ifreq ifr;
1638cf6c252SPaul Traina 	struct bpf_version bv;
1648cf6c252SPaul Traina 	u_int v;
1658cf6c252SPaul Traina 	pcap_t *p;
1668cf6c252SPaul Traina 
1678cf6c252SPaul Traina 	p = (pcap_t *)malloc(sizeof(*p));
1688cf6c252SPaul Traina 	if (p == NULL) {
1698cf6c252SPaul Traina 		sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
1708cf6c252SPaul Traina 		return (NULL);
1718cf6c252SPaul Traina 	}
1728cf6c252SPaul Traina 	bzero(p, sizeof(*p));
1738cf6c252SPaul Traina 	fd = bpf_open(p, ebuf);
1748cf6c252SPaul Traina 	if (fd < 0)
1758cf6c252SPaul Traina 		goto bad;
1768cf6c252SPaul Traina 
1778cf6c252SPaul Traina 	p->fd = fd;
1788cf6c252SPaul Traina 	p->snapshot = snaplen;
1798cf6c252SPaul Traina 
1808cf6c252SPaul Traina 	if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) {
1818cf6c252SPaul Traina 		sprintf(ebuf, "BIOCVERSION: %s", pcap_strerror(errno));
1828cf6c252SPaul Traina 		goto bad;
1838cf6c252SPaul Traina 	}
1848cf6c252SPaul Traina 	if (bv.bv_major != BPF_MAJOR_VERSION ||
1858cf6c252SPaul Traina 	    bv.bv_minor < BPF_MINOR_VERSION) {
1868cf6c252SPaul Traina 		sprintf(ebuf, "kernel bpf filter out of date");
1878cf6c252SPaul Traina 		goto bad;
1888cf6c252SPaul Traina 	}
189a4b5b39fSBill Fenner 	v = 32768;	/* XXX this should be a user-accessible hook */
190a4b5b39fSBill Fenner 	/* Ignore the return value - this is because the call fails on
191a4b5b39fSBill Fenner 	 * BPF systems that don't have kernel malloc.  And if the call
192a4b5b39fSBill Fenner 	 * fails, it's no big deal, we just continue to use the standard
193a4b5b39fSBill Fenner 	 * buffer size.
194a4b5b39fSBill Fenner 	 */
195a4b5b39fSBill Fenner 	(void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
196a4b5b39fSBill Fenner 
1978cf6c252SPaul Traina 	(void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
1988cf6c252SPaul Traina 	if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
1998cf6c252SPaul Traina 		sprintf(ebuf, "%s: %s", device, pcap_strerror(errno));
2008cf6c252SPaul Traina 		goto bad;
2018cf6c252SPaul Traina 	}
2028cf6c252SPaul Traina 	/* Get the data link layer type. */
2038cf6c252SPaul Traina 	if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
2048cf6c252SPaul Traina 		sprintf(ebuf, "BIOCGDLT: %s", pcap_strerror(errno));
2058cf6c252SPaul Traina 		goto bad;
2068cf6c252SPaul Traina 	}
2078751327cSBill Fenner #ifdef __OpenBSD__
2088751327cSBill Fenner 	switch (v) {
2098751327cSBill Fenner 	case DLT_LOOP:
2108751327cSBill Fenner 		v = DLT_NULL;
2118751327cSBill Fenner 		break;
2128751327cSBill Fenner 	}
2138751327cSBill Fenner #endif
214a4b5b39fSBill Fenner #if _BSDI_VERSION - 0 >= 199510
215a4b5b39fSBill Fenner 	/* The SLIP and PPP link layer header changed in BSD/OS 2.1 */
216a4b5b39fSBill Fenner 	switch (v) {
217a4b5b39fSBill Fenner 
218a4b5b39fSBill Fenner 	case DLT_SLIP:
219a4b5b39fSBill Fenner 		v = DLT_SLIP_BSDOS;
220a4b5b39fSBill Fenner 		break;
221a4b5b39fSBill Fenner 
222a4b5b39fSBill Fenner 	case DLT_PPP:
223a4b5b39fSBill Fenner 		v = DLT_PPP_BSDOS;
224a4b5b39fSBill Fenner 		break;
2258751327cSBill Fenner 
2268751327cSBill Fenner 	case 11:	/*DLT_FR*/
2278751327cSBill Fenner 		v = DLT_RAW;	/*XXX*/
2288751327cSBill Fenner 		break;
2298751327cSBill Fenner 
2308751327cSBill Fenner 	case 12:	/*DLT_C_HDLC*/
2318751327cSBill Fenner 		v = DLT_CHDLC;
2328751327cSBill Fenner 		break;
233a4b5b39fSBill Fenner 	}
234a4b5b39fSBill Fenner #endif
2358cf6c252SPaul Traina 	p->linktype = v;
2368cf6c252SPaul Traina 
2378cf6c252SPaul Traina 	/* set timeout */
2388cf6c252SPaul Traina 	if (to_ms != 0) {
2398cf6c252SPaul Traina 		struct timeval to;
2408cf6c252SPaul Traina 		to.tv_sec = to_ms / 1000;
2418cf6c252SPaul Traina 		to.tv_usec = (to_ms * 1000) % 1000000;
2428cf6c252SPaul Traina 		if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&to) < 0) {
2438cf6c252SPaul Traina 			sprintf(ebuf, "BIOCSRTIMEOUT: %s",
2448cf6c252SPaul Traina 				pcap_strerror(errno));
2458cf6c252SPaul Traina 			goto bad;
2468cf6c252SPaul Traina 		}
2478cf6c252SPaul Traina 	}
2488cf6c252SPaul Traina 	if (promisc)
2498cf6c252SPaul Traina 		/* set promiscuous mode, okay if it fails */
2508cf6c252SPaul Traina 		(void)ioctl(p->fd, BIOCPROMISC, NULL);
2518cf6c252SPaul Traina 
2528cf6c252SPaul Traina 	if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
2538cf6c252SPaul Traina 		sprintf(ebuf, "BIOCGBLEN: %s", pcap_strerror(errno));
2548cf6c252SPaul Traina 		goto bad;
2558cf6c252SPaul Traina 	}
2568cf6c252SPaul Traina 	p->bufsize = v;
2578cf6c252SPaul Traina 	p->buffer = (u_char *)malloc(p->bufsize);
2588cf6c252SPaul Traina 	if (p->buffer == NULL) {
2598cf6c252SPaul Traina 		sprintf(ebuf, "malloc: %s", pcap_strerror(errno));
2608cf6c252SPaul Traina 		goto bad;
2618cf6c252SPaul Traina 	}
2628cf6c252SPaul Traina 
2638cf6c252SPaul Traina 	return (p);
2648cf6c252SPaul Traina  bad:
2658cf6c252SPaul Traina 	(void)close(fd);
2668cf6c252SPaul Traina 	free(p);
2678cf6c252SPaul Traina 	return (NULL);
2688cf6c252SPaul Traina }
2698cf6c252SPaul Traina 
2708cf6c252SPaul Traina int
2718cf6c252SPaul Traina pcap_setfilter(pcap_t *p, struct bpf_program *fp)
2728cf6c252SPaul Traina {
2738751327cSBill Fenner 	/*
2748751327cSBill Fenner 	 * It looks that BPF code generated by gen_protochain() is not
2758751327cSBill Fenner 	 * compatible with some of kernel BPF code (for example BSD/OS 3.1).
2768751327cSBill Fenner 	 * Take a safer side for now.
2778751327cSBill Fenner 	 */
2788751327cSBill Fenner 	if (no_optimize)
2798751327cSBill Fenner 		p->fcode = *fp;
2808751327cSBill Fenner 	else if (p->sf.rfile != NULL)
2818cf6c252SPaul Traina 		p->fcode = *fp;
2828cf6c252SPaul Traina 	else if (ioctl(p->fd, BIOCSETF, (caddr_t)fp) < 0) {
2838cf6c252SPaul Traina 		sprintf(p->errbuf, "BIOCSETF: %s", pcap_strerror(errno));
2848cf6c252SPaul Traina 		return (-1);
2858cf6c252SPaul Traina 	}
2868cf6c252SPaul Traina 	return (0);
2878cf6c252SPaul Traina }
288