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