11592Srgrimes/* 21592Srgrimes * Copyright (c) 1988, 1992 The University of Utah and the Center 31592Srgrimes * for Software Science (CSS). 41592Srgrimes * Copyright (c) 1992, 1993 51592Srgrimes * The Regents of the University of California. All rights reserved. 61592Srgrimes * 71592Srgrimes * This code is derived from software contributed to Berkeley by 81592Srgrimes * the Center for Software Science of the University of Utah Computer 91592Srgrimes * Science Department. CSS requests users of this software to return 101592Srgrimes * to css-dist@cs.utah.edu any improvements that they make and grant 111592Srgrimes * CSS redistribution rights. 121592Srgrimes * 131592Srgrimes * Redistribution and use in source and binary forms, with or without 141592Srgrimes * modification, are permitted provided that the following conditions 151592Srgrimes * are met: 161592Srgrimes * 1. Redistributions of source code must retain the above copyright 171592Srgrimes * notice, this list of conditions and the following disclaimer. 181592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 191592Srgrimes * notice, this list of conditions and the following disclaimer in the 201592Srgrimes * documentation and/or other materials provided with the distribution. 21262435Sbrueffer * 3. Neither the name of the University nor the names of its contributors 221592Srgrimes * may be used to endorse or promote products derived from this software 231592Srgrimes * without specific prior written permission. 241592Srgrimes * 251592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 261592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 271592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 281592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 291592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 301592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 311592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 321592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 331592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 341592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 351592Srgrimes * SUCH DAMAGE. 361592Srgrimes * 3727077Ssteve * from: @(#)bpf.c 8.1 (Berkeley) 6/4/93 381592Srgrimes * 3927077Ssteve * From: Utah Hdr: bpf.c 3.1 92/07/06 401592Srgrimes * Author: Jeff Forys, University of Utah CSS 411592Srgrimes */ 421592Srgrimes 431592Srgrimes#ifndef lint 4431386Scharnier#if 0 4527077Sstevestatic const char sccsid[] = "@(#)bpf.c 8.1 (Berkeley) 6/4/93"; 4631386Scharnier#endif 4731386Scharnierstatic const char rcsid[] = 4850476Speter "$FreeBSD$"; 491592Srgrimes#endif /* not lint */ 501592Srgrimes 511592Srgrimes#include <sys/param.h> 521592Srgrimes#include <sys/ioctl.h> 531592Srgrimes#include <sys/socket.h> 5420287Swollman#include <sys/time.h> 551592Srgrimes 561592Srgrimes#include <net/if.h> 571592Srgrimes#include <net/bpf.h> 581592Srgrimes 591592Srgrimes#include <ctype.h> 601592Srgrimes#include <errno.h> 611592Srgrimes#include <fcntl.h> 621592Srgrimes#include <stdio.h> 631592Srgrimes#include <stdlib.h> 641592Srgrimes#include <string.h> 651592Srgrimes#include <syslog.h> 661592Srgrimes#include <unistd.h> 671592Srgrimes#include "defs.h" 681592Srgrimes#include "pathnames.h" 691592Srgrimes 701592Srgrimesstatic int BpfFd = -1; 711592Srgrimesstatic unsigned BpfLen = 0; 7227077Sstevestatic u_int8_t *BpfPkt = NULL; 731592Srgrimes 741592Srgrimes/* 751592Srgrimes** BpfOpen -- Open and initialize a BPF device. 761592Srgrimes** 771592Srgrimes** Parameters: 781592Srgrimes** None. 791592Srgrimes** 801592Srgrimes** Returns: 811592Srgrimes** File descriptor of opened BPF device (for select() etc). 821592Srgrimes** 831592Srgrimes** Side Effects: 841592Srgrimes** If an error is encountered, the program terminates here. 851592Srgrimes*/ 861592Srgrimesint 8790377SimpBpfOpen(void) 881592Srgrimes{ 891592Srgrimes struct ifreq ifr; 901592Srgrimes char bpfdev[32]; 911592Srgrimes int n = 0; 921592Srgrimes 931592Srgrimes /* 941592Srgrimes * Open the first available BPF device. 951592Srgrimes */ 961592Srgrimes do { 971592Srgrimes (void) sprintf(bpfdev, _PATH_BPF, n++); 981592Srgrimes BpfFd = open(bpfdev, O_RDWR); 991592Srgrimes } while (BpfFd < 0 && (errno == EBUSY || errno == EPERM)); 1001592Srgrimes 1011592Srgrimes if (BpfFd < 0) { 1021592Srgrimes syslog(LOG_ERR, "bpf: no available devices: %m"); 1031592Srgrimes Exit(0); 1041592Srgrimes } 1051592Srgrimes 1061592Srgrimes /* 1071592Srgrimes * Set interface name for bpf device, get data link layer 1081592Srgrimes * type and make sure it's type Ethernet. 1091592Srgrimes */ 1101592Srgrimes (void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name)); 1111592Srgrimes if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) { 1121592Srgrimes syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName); 1131592Srgrimes Exit(0); 1141592Srgrimes } 1151592Srgrimes 1161592Srgrimes /* 1171592Srgrimes * Make sure we are dealing with an Ethernet device. 1181592Srgrimes */ 1191592Srgrimes if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) { 1201592Srgrimes syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m"); 1211592Srgrimes Exit(0); 1221592Srgrimes } 1231592Srgrimes if (n != DLT_EN10MB) { 1241592Srgrimes syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported", 1251592Srgrimes IntfName, n); 1261592Srgrimes Exit(0); 1271592Srgrimes } 1281592Srgrimes 1291592Srgrimes /* 1301592Srgrimes * On read(), return packets immediately (do not buffer them). 1311592Srgrimes */ 1321592Srgrimes n = 1; 1331592Srgrimes if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) { 1341592Srgrimes syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m"); 1351592Srgrimes Exit(0); 1361592Srgrimes } 1371592Srgrimes 1381592Srgrimes /* 1391592Srgrimes * Try to enable the chip/driver's multicast address filter to 1401592Srgrimes * grab our RMP address. If this fails, try promiscuous mode. 1411592Srgrimes * If this fails, there's no way we are going to get any RMP 1421592Srgrimes * packets so just exit here. 1431592Srgrimes */ 1441592Srgrimes#ifdef MSG_EOR 1451592Srgrimes ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; 1461592Srgrimes#endif 1471592Srgrimes ifr.ifr_addr.sa_family = AF_UNSPEC; 14827079Ssteve memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0], RMP_ADDRLEN); 14927077Ssteve if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) { 15027077Ssteve syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m"); 15127077Ssteve Exit(0); 1521592Srgrimes } 1531592Srgrimes 1541592Srgrimes /* 1551592Srgrimes * Ask BPF how much buffer space it requires and allocate one. 1561592Srgrimes */ 1571592Srgrimes if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) { 1581592Srgrimes syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m"); 1591592Srgrimes Exit(0); 1601592Srgrimes } 1611592Srgrimes if (BpfPkt == NULL) 16227077Ssteve BpfPkt = (u_int8_t *)malloc(BpfLen); 1631592Srgrimes 1641592Srgrimes if (BpfPkt == NULL) { 1651592Srgrimes syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)", 1661592Srgrimes BpfLen); 1671592Srgrimes Exit(0); 1681592Srgrimes } 1691592Srgrimes 1701592Srgrimes /* 1711592Srgrimes * Write a little program to snarf RMP Boot packets and stuff 1721592Srgrimes * it down BPF's throat (i.e. set up the packet filter). 1731592Srgrimes */ 1741592Srgrimes { 1751592Srgrimes#define RMP ((struct rmp_packet *)0) 1761592Srgrimes static struct bpf_insn bpf_insn[] = { 1771592Srgrimes { BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap }, 1781592Srgrimes { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP }, 1791592Srgrimes { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl }, 1801592Srgrimes { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP }, 1811592Srgrimes { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap }, 1821592Srgrimes { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP }, 1831592Srgrimes { BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET }, 1841592Srgrimes { BPF_RET|BPF_K, 0, 0, 0x0 } 1851592Srgrimes }; 1861592Srgrimes#undef RMP 1871592Srgrimes static struct bpf_program bpf_pgm = { 1881592Srgrimes sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn 1891592Srgrimes }; 1901592Srgrimes 1911592Srgrimes if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) { 1921592Srgrimes syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m"); 1931592Srgrimes Exit(0); 1941592Srgrimes } 1951592Srgrimes } 1961592Srgrimes 1971592Srgrimes return(BpfFd); 1981592Srgrimes} 1991592Srgrimes 2001592Srgrimes/* 2011592Srgrimes** BPF GetIntfName -- Return the name of a network interface attached to 2021592Srgrimes** the system, or 0 if none can be found. The interface 2031592Srgrimes** must be configured up; the lowest unit number is 2041592Srgrimes** preferred; loopback is ignored. 2051592Srgrimes** 2061592Srgrimes** Parameters: 2071592Srgrimes** errmsg - if no network interface found, *errmsg explains why. 2081592Srgrimes** 2091592Srgrimes** Returns: 2101592Srgrimes** A (static) pointer to interface name, or NULL on error. 2111592Srgrimes** 2121592Srgrimes** Side Effects: 2131592Srgrimes** None. 2141592Srgrimes*/ 2151592Srgrimeschar * 21690377SimpBpfGetIntfName(char **errmsg) 2171592Srgrimes{ 2181592Srgrimes struct ifreq ibuf[8], *ifrp, *ifend, *mp; 2191592Srgrimes struct ifconf ifc; 2201592Srgrimes int fd; 2211592Srgrimes int minunit, n; 2221592Srgrimes char *cp; 2231592Srgrimes static char device[sizeof(ifrp->ifr_name)]; 2241592Srgrimes static char errbuf[128] = "No Error!"; 2251592Srgrimes 2261592Srgrimes if (errmsg != NULL) 2271592Srgrimes *errmsg = errbuf; 2281592Srgrimes 2291592Srgrimes if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 2301592Srgrimes (void) strcpy(errbuf, "bpf: socket: %m"); 2311592Srgrimes return(NULL); 2321592Srgrimes } 2331592Srgrimes ifc.ifc_len = sizeof ibuf; 2341592Srgrimes ifc.ifc_buf = (caddr_t)ibuf; 2351592Srgrimes 2361592Srgrimes#ifdef OSIOCGIFCONF 2371592Srgrimes if (ioctl(fd, OSIOCGIFCONF, (char *)&ifc) < 0 || 2381592Srgrimes ifc.ifc_len < sizeof(struct ifreq)) { 2391592Srgrimes (void) strcpy(errbuf, "bpf: ioctl(OSIOCGIFCONF): %m"); 2401592Srgrimes return(NULL); 2411592Srgrimes } 2421592Srgrimes#else 2431592Srgrimes if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || 2441592Srgrimes ifc.ifc_len < sizeof(struct ifreq)) { 2451592Srgrimes (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m"); 2461592Srgrimes return(NULL); 2471592Srgrimes } 2481592Srgrimes#endif 2491592Srgrimes ifrp = ibuf; 2501592Srgrimes ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); 2518870Srgrimes 2521592Srgrimes mp = 0; 2531592Srgrimes minunit = 666; 2541592Srgrimes for (; ifrp < ifend; ++ifrp) { 2551592Srgrimes if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) { 2561592Srgrimes (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m"); 2571592Srgrimes return(NULL); 2581592Srgrimes } 2591592Srgrimes 2601592Srgrimes /* 2611592Srgrimes * If interface is down or this is the loopback interface, 2621592Srgrimes * ignore it. 2631592Srgrimes */ 2641592Srgrimes if ((ifrp->ifr_flags & IFF_UP) == 0 || 2651592Srgrimes#ifdef IFF_LOOPBACK 2661592Srgrimes (ifrp->ifr_flags & IFF_LOOPBACK)) 2671592Srgrimes#else 2681592Srgrimes (strcmp(ifrp->ifr_name, "lo0") == 0)) 2691592Srgrimes#endif 2701592Srgrimes continue; 2711592Srgrimes 2721592Srgrimes for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp) 2731592Srgrimes ; 2741592Srgrimes n = atoi(cp); 2751592Srgrimes if (n < minunit) { 2761592Srgrimes minunit = n; 2771592Srgrimes mp = ifrp; 2781592Srgrimes } 2791592Srgrimes } 2801592Srgrimes 2811592Srgrimes (void) close(fd); 2821592Srgrimes if (mp == 0) { 2831592Srgrimes (void) strcpy(errbuf, "bpf: no interfaces found"); 2841592Srgrimes return(NULL); 2851592Srgrimes } 2861592Srgrimes 2871592Srgrimes (void) strcpy(device, mp->ifr_name); 2881592Srgrimes return(device); 2891592Srgrimes} 2901592Srgrimes 2911592Srgrimes/* 2921592Srgrimes** BpfRead -- Read packets from a BPF device and fill in `rconn'. 2931592Srgrimes** 2941592Srgrimes** Parameters: 2951592Srgrimes** rconn - filled in with next packet. 2961592Srgrimes** doread - is True if we can issue a read() syscall. 2971592Srgrimes** 2981592Srgrimes** Returns: 2991592Srgrimes** True if `rconn' contains a new packet, False otherwise. 3001592Srgrimes** 3011592Srgrimes** Side Effects: 3021592Srgrimes** None. 3031592Srgrimes*/ 3041592Srgrimesint 30590377SimpBpfRead(RMPCONN *rconn, int doread) 3061592Srgrimes{ 30727079Ssteve int datlen, caplen, hdrlen; 30827077Ssteve static u_int8_t *bp = NULL, *ep = NULL; 3091592Srgrimes int cc; 3101592Srgrimes 3111592Srgrimes /* 3121592Srgrimes * The read() may block, or it may return one or more packets. 3131592Srgrimes * We let the caller decide whether or not we can issue a read(). 3141592Srgrimes */ 3151592Srgrimes if (doread) { 3161592Srgrimes if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) { 3171592Srgrimes syslog(LOG_ERR, "bpf: read: %m"); 3181592Srgrimes return(0); 3191592Srgrimes } else { 3201592Srgrimes bp = BpfPkt; 3211592Srgrimes ep = BpfPkt + cc; 3221592Srgrimes } 3231592Srgrimes } 3241592Srgrimes 3251592Srgrimes#define bhp ((struct bpf_hdr *)bp) 3261592Srgrimes /* 3271592Srgrimes * If there is a new packet in the buffer, stuff it into `rconn' 3281592Srgrimes * and return a success indication. 3291592Srgrimes */ 3301592Srgrimes if (bp < ep) { 3311592Srgrimes datlen = bhp->bh_datalen; 3321592Srgrimes caplen = bhp->bh_caplen; 3331592Srgrimes hdrlen = bhp->bh_hdrlen; 3341592Srgrimes 3351592Srgrimes if (caplen != datlen) 3361592Srgrimes syslog(LOG_ERR, 3371592Srgrimes "bpf: short packet dropped (%d of %d bytes)", 3381592Srgrimes caplen, datlen); 3391592Srgrimes else if (caplen > sizeof(struct rmp_packet)) 3401592Srgrimes syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)", 3411592Srgrimes caplen); 3421592Srgrimes else { 3431592Srgrimes rconn->rmplen = caplen; 34427079Ssteve memmove((char *)&rconn->tstamp, (char *)&bhp->bh_tstamp, 3451592Srgrimes sizeof(struct timeval)); 34627079Ssteve memmove((char *)&rconn->rmp, (char *)bp + hdrlen, caplen); 3471592Srgrimes } 3481592Srgrimes bp += BPF_WORDALIGN(caplen + hdrlen); 3491592Srgrimes return(1); 3501592Srgrimes } 3511592Srgrimes#undef bhp 3521592Srgrimes 3531592Srgrimes return(0); 3541592Srgrimes} 3551592Srgrimes 3561592Srgrimes/* 3571592Srgrimes** BpfWrite -- Write packet to BPF device. 3581592Srgrimes** 3591592Srgrimes** Parameters: 3601592Srgrimes** rconn - packet to send. 3611592Srgrimes** 3621592Srgrimes** Returns: 3631592Srgrimes** True if write succeeded, False otherwise. 3641592Srgrimes** 3651592Srgrimes** Side Effects: 3661592Srgrimes** None. 3671592Srgrimes*/ 3681592Srgrimesint 36990377SimpBpfWrite(RMPCONN *rconn) 3701592Srgrimes{ 3711592Srgrimes if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) { 3721592Srgrimes syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn)); 3731592Srgrimes return(0); 3741592Srgrimes } 3751592Srgrimes 3761592Srgrimes return(1); 3771592Srgrimes} 3781592Srgrimes 3791592Srgrimes/* 3801592Srgrimes** BpfClose -- Close a BPF device. 3811592Srgrimes** 3821592Srgrimes** Parameters: 3831592Srgrimes** None. 3841592Srgrimes** 3851592Srgrimes** Returns: 3861592Srgrimes** Nothing. 3871592Srgrimes** 3881592Srgrimes** Side Effects: 3891592Srgrimes** None. 3901592Srgrimes*/ 3911592Srgrimesvoid 39290377SimpBpfClose(void) 3931592Srgrimes{ 3941592Srgrimes struct ifreq ifr; 3951592Srgrimes 3961592Srgrimes if (BpfPkt != NULL) { 3971592Srgrimes free((char *)BpfPkt); 3981592Srgrimes BpfPkt = NULL; 3991592Srgrimes } 4001592Srgrimes 4011592Srgrimes if (BpfFd == -1) 4021592Srgrimes return; 4031592Srgrimes 4041592Srgrimes#ifdef MSG_EOR 4051592Srgrimes ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; 4061592Srgrimes#endif 4071592Srgrimes ifr.ifr_addr.sa_family = AF_UNSPEC; 40827079Ssteve memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0], RMP_ADDRLEN); 4091592Srgrimes if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0) 4101592Srgrimes (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0); 4111592Srgrimes 4121592Srgrimes (void) close(BpfFd); 4131592Srgrimes BpfFd = -1; 4141592Srgrimes} 415