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