xref: /csrg-svn/libexec/rbootd/bpf.c (revision 55569)
1*55569Sbostic /*
2*55569Sbostic  * Copyright (c) 1992 Regents of the University of California.
3*55569Sbostic  * Copyright (c) 1988, 1992 The University of Utah and the Center
4*55569Sbostic  *	for Software Science (CSS).
5*55569Sbostic  * All rights reserved.
6*55569Sbostic  *
7*55569Sbostic  * This code is derived from software contributed to Berkeley by
8*55569Sbostic  * the Center for Software Science of the University of Utah Computer
9*55569Sbostic  * Science Department.  CSS requests users of this software to return
10*55569Sbostic  * to css-dist@cs.utah.edu any improvements that they make and grant
11*55569Sbostic  * CSS redistribution rights.
12*55569Sbostic  *
13*55569Sbostic  * %sccs.include.redist.c%
14*55569Sbostic  *
15*55569Sbostic  *	@(#)bpf.c	5.1 (Berkeley) 07/23/92
16*55569Sbostic  *
17*55569Sbostic  * Utah $Hdr: bpf.c 3.1 92/07/06$
18*55569Sbostic  * Author: Jeff Forys, University of Utah CSS
19*55569Sbostic  */
20*55569Sbostic 
21*55569Sbostic #ifndef lint
22*55569Sbostic static char sccsid[] = "@(#)bpf.c	5.1 (Berkeley) 07/23/92";
23*55569Sbostic #endif /* not lint */
24*55569Sbostic 
25*55569Sbostic #include "defs.h"
26*55569Sbostic 
27*55569Sbostic #include <ctype.h>
28*55569Sbostic #include <syslog.h>
29*55569Sbostic #include <strings.h>
30*55569Sbostic 
31*55569Sbostic #include <sys/ioctl.h>
32*55569Sbostic #include <sys/file.h>
33*55569Sbostic #include <sys/errno.h>
34*55569Sbostic 
35*55569Sbostic #include <net/if.h>
36*55569Sbostic #include <net/bpf.h>
37*55569Sbostic 
38*55569Sbostic #include "pathnames.h"
39*55569Sbostic 
40*55569Sbostic extern int errno;
41*55569Sbostic 
42*55569Sbostic static int BpfFd = -1;
43*55569Sbostic static unsigned BpfLen = 0;
44*55569Sbostic static u_char *BpfPkt = NULL;
45*55569Sbostic 
46*55569Sbostic /*
47*55569Sbostic **  BpfOpen -- Open and initialize a BPF device.
48*55569Sbostic **
49*55569Sbostic **	Parameters:
50*55569Sbostic **		None.
51*55569Sbostic **
52*55569Sbostic **	Returns:
53*55569Sbostic **		File descriptor of opened BPF device (for select() etc).
54*55569Sbostic **
55*55569Sbostic **	Side Effects:
56*55569Sbostic **		If an error is encountered, the program terminates here.
57*55569Sbostic */
58*55569Sbostic 
59*55569Sbostic int
60*55569Sbostic BpfOpen()
61*55569Sbostic {
62*55569Sbostic 	struct ifreq ifr;
63*55569Sbostic 	char bpfdev[32];
64*55569Sbostic 	int n = 0;
65*55569Sbostic 
66*55569Sbostic 	/*
67*55569Sbostic 	 *  Open the first available BPF device.
68*55569Sbostic 	 */
69*55569Sbostic 	do {
70*55569Sbostic 		(void) sprintf(bpfdev, _PATH_BPF, n++);
71*55569Sbostic 		BpfFd = open(bpfdev, O_RDWR);
72*55569Sbostic 	} while (BpfFd < 0 && (errno == EBUSY || errno == EPERM));
73*55569Sbostic 
74*55569Sbostic 	if (BpfFd < 0) {
75*55569Sbostic 		syslog(LOG_ERR, "bpf: no available devices: %m");
76*55569Sbostic 		Exit(0);
77*55569Sbostic 	}
78*55569Sbostic 
79*55569Sbostic 	/*
80*55569Sbostic 	 *  Set interface name for bpf device, get data link layer
81*55569Sbostic 	 *  type and make sure it's type Ethernet.
82*55569Sbostic 	 */
83*55569Sbostic 	(void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name));
84*55569Sbostic 	if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) {
85*55569Sbostic 		syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName);
86*55569Sbostic 		Exit(0);
87*55569Sbostic 	}
88*55569Sbostic 
89*55569Sbostic 	/*
90*55569Sbostic 	 *  Make sure we are dealing with an Ethernet device.
91*55569Sbostic 	 */
92*55569Sbostic 	if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) {
93*55569Sbostic 		syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m");
94*55569Sbostic 		Exit(0);
95*55569Sbostic 	}
96*55569Sbostic 	if (n != DLT_EN10MB) {
97*55569Sbostic 		syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported",
98*55569Sbostic 		       IntfName, n);
99*55569Sbostic 		Exit(0);
100*55569Sbostic 	}
101*55569Sbostic 
102*55569Sbostic 	/*
103*55569Sbostic 	 *  On read(), return packets immediately (do not buffer them).
104*55569Sbostic 	 */
105*55569Sbostic 	n = 1;
106*55569Sbostic 	if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) {
107*55569Sbostic 		syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m");
108*55569Sbostic 		Exit(0);
109*55569Sbostic 	}
110*55569Sbostic 
111*55569Sbostic 	/*
112*55569Sbostic 	 *  Try to enable the chip/driver's multicast address filter to
113*55569Sbostic 	 *  grab our RMP address.  If this fails, try promiscuous mode.
114*55569Sbostic 	 *  If this fails, there's no way we are going to get any RMP
115*55569Sbostic 	 *  packets so just exit here.
116*55569Sbostic 	 */
117*55569Sbostic #ifdef MSG_EOR
118*55569Sbostic 	ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
119*55569Sbostic #endif
120*55569Sbostic 	ifr.ifr_addr.sa_family = AF_UNSPEC;
121*55569Sbostic 	bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN);
122*55569Sbostic 	if (ioctl(BpfFd, SIOCADDMULTI, (caddr_t)&ifr) < 0) {
123*55569Sbostic 		syslog(LOG_WARNING,
124*55569Sbostic 		    "bpf: can't add mcast addr (%m), setting promiscuous mode");
125*55569Sbostic 
126*55569Sbostic 		if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) {
127*55569Sbostic 			syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m");
128*55569Sbostic 			Exit(0);
129*55569Sbostic 		}
130*55569Sbostic 	}
131*55569Sbostic 
132*55569Sbostic 	/*
133*55569Sbostic 	 *  Ask BPF how much buffer space it requires and allocate one.
134*55569Sbostic 	 */
135*55569Sbostic 	if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) {
136*55569Sbostic 		syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m");
137*55569Sbostic 		Exit(0);
138*55569Sbostic 	}
139*55569Sbostic 	if (BpfPkt == NULL)
140*55569Sbostic 		BpfPkt = (u_char *)malloc(BpfLen);
141*55569Sbostic 
142*55569Sbostic 	if (BpfPkt == NULL) {
143*55569Sbostic 		syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)",
144*55569Sbostic 		       BpfLen);
145*55569Sbostic 		Exit(0);
146*55569Sbostic 	}
147*55569Sbostic 
148*55569Sbostic 	/*
149*55569Sbostic 	 *  Write a little program to snarf RMP Boot packets and stuff
150*55569Sbostic 	 *  it down BPF's throat (i.e. set up the packet filter).
151*55569Sbostic 	 */
152*55569Sbostic 	{
153*55569Sbostic #define	RMP	((struct rmp_packet *)0)
154*55569Sbostic 		static struct bpf_insn bpf_insn[] = {
155*55569Sbostic 		    { BPF_LD|BPF_B|BPF_ABS,  0, 0, (long)&RMP->hp_llc.dsap },
156*55569Sbostic 		    { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP },
157*55569Sbostic 		    { BPF_LD|BPF_H|BPF_ABS,  0, 0, (long)&RMP->hp_llc.cntrl },
158*55569Sbostic 		    { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP },
159*55569Sbostic 		    { BPF_LD|BPF_H|BPF_ABS,  0, 0, (long)&RMP->hp_llc.dxsap },
160*55569Sbostic 		    { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP },
161*55569Sbostic 		    { BPF_RET|BPF_K,         0, 0, RMP_MAX_PACKET },
162*55569Sbostic 		    { BPF_RET|BPF_K,         0, 0, 0x0 }
163*55569Sbostic 		};
164*55569Sbostic #undef	RMP
165*55569Sbostic 		static struct bpf_program bpf_pgm = {
166*55569Sbostic 		    sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn
167*55569Sbostic 		};
168*55569Sbostic 
169*55569Sbostic 		if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) {
170*55569Sbostic 			syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m");
171*55569Sbostic 			Exit(0);
172*55569Sbostic 		}
173*55569Sbostic 	}
174*55569Sbostic 
175*55569Sbostic 	return(BpfFd);
176*55569Sbostic }
177*55569Sbostic 
178*55569Sbostic /*
179*55569Sbostic **  BPF GetIntfName -- Return the name of a network interface attached to
180*55569Sbostic **		the system, or 0 if none can be found.  The interface
181*55569Sbostic **		must be configured up; the lowest unit number is
182*55569Sbostic **		preferred; loopback is ignored.
183*55569Sbostic **
184*55569Sbostic **	Parameters:
185*55569Sbostic **		errmsg - if no network interface found, *errmsg explains why.
186*55569Sbostic **
187*55569Sbostic **	Returns:
188*55569Sbostic **		A (static) pointer to interface name, or NULL on error.
189*55569Sbostic **
190*55569Sbostic **	Side Effects:
191*55569Sbostic **		None.
192*55569Sbostic */
193*55569Sbostic 
194*55569Sbostic char *
195*55569Sbostic BpfGetIntfName(errmsg)
196*55569Sbostic 	char **errmsg;
197*55569Sbostic {
198*55569Sbostic 	struct ifreq ibuf[8], *ifrp, *ifend, *mp;
199*55569Sbostic 	struct ifconf ifc;
200*55569Sbostic 	int fd;
201*55569Sbostic 	int minunit, n;
202*55569Sbostic 	char *cp;
203*55569Sbostic 	static char device[sizeof(ifrp->ifr_name)];
204*55569Sbostic 	static char errbuf[128] = "No Error!";
205*55569Sbostic 
206*55569Sbostic 	if (errmsg != NULL)
207*55569Sbostic 		*errmsg = errbuf;
208*55569Sbostic 
209*55569Sbostic 	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
210*55569Sbostic 		(void) strcpy(errbuf, "bpf: socket: %m");
211*55569Sbostic 		return(NULL);
212*55569Sbostic 	}
213*55569Sbostic 	ifc.ifc_len = sizeof ibuf;
214*55569Sbostic 	ifc.ifc_buf = (caddr_t)ibuf;
215*55569Sbostic 
216*55569Sbostic #ifdef OSIOCGIFCONF
217*55569Sbostic 	if (ioctl(fd, OSIOCGIFCONF, (char *)&ifc) < 0 ||
218*55569Sbostic 	    ifc.ifc_len < sizeof(struct ifreq)) {
219*55569Sbostic 		(void) strcpy(errbuf, "bpf: ioctl(OSIOCGIFCONF): %m");
220*55569Sbostic 		return(NULL);
221*55569Sbostic 	}
222*55569Sbostic #else
223*55569Sbostic 	if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
224*55569Sbostic 	    ifc.ifc_len < sizeof(struct ifreq)) {
225*55569Sbostic 		(void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m");
226*55569Sbostic 		return(NULL);
227*55569Sbostic 	}
228*55569Sbostic #endif
229*55569Sbostic 	ifrp = ibuf;
230*55569Sbostic 	ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
231*55569Sbostic 
232*55569Sbostic 	mp = 0;
233*55569Sbostic 	minunit = 666;
234*55569Sbostic 	for (; ifrp < ifend; ++ifrp) {
235*55569Sbostic 		if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) {
236*55569Sbostic 			(void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m");
237*55569Sbostic 			return(NULL);
238*55569Sbostic 		}
239*55569Sbostic 
240*55569Sbostic 		/*
241*55569Sbostic 		 *  If interface is down or this is the loopback interface,
242*55569Sbostic 		 *  ignore it.
243*55569Sbostic 		 */
244*55569Sbostic 		if ((ifrp->ifr_flags & IFF_UP) == 0 ||
245*55569Sbostic #ifdef IFF_LOOPBACK
246*55569Sbostic 		    (ifrp->ifr_flags & IFF_LOOPBACK))
247*55569Sbostic #else
248*55569Sbostic 		    (strcmp(ifrp->ifr_name, "lo0") == 0))
249*55569Sbostic #endif
250*55569Sbostic 			continue;
251*55569Sbostic 
252*55569Sbostic 		for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
253*55569Sbostic 			;
254*55569Sbostic 		n = atoi(cp);
255*55569Sbostic 		if (n < minunit) {
256*55569Sbostic 			minunit = n;
257*55569Sbostic 			mp = ifrp;
258*55569Sbostic 		}
259*55569Sbostic 	}
260*55569Sbostic 
261*55569Sbostic 	(void) close(fd);
262*55569Sbostic 	if (mp == 0) {
263*55569Sbostic 		(void) strcpy(errbuf, "bpf: no interfaces found");
264*55569Sbostic 		return(NULL);
265*55569Sbostic 	}
266*55569Sbostic 
267*55569Sbostic 	(void) strcpy(device, mp->ifr_name);
268*55569Sbostic 	return(device);
269*55569Sbostic }
270*55569Sbostic 
271*55569Sbostic /*
272*55569Sbostic **  BpfRead -- Read packets from a BPF device and fill in `rconn'.
273*55569Sbostic **
274*55569Sbostic **	Parameters:
275*55569Sbostic **		rconn - filled in with next packet.
276*55569Sbostic **		doread - is True if we can issue a read() syscall.
277*55569Sbostic **
278*55569Sbostic **	Returns:
279*55569Sbostic **		True if `rconn' contains a new packet, False otherwise.
280*55569Sbostic **
281*55569Sbostic **	Side Effects:
282*55569Sbostic **		None.
283*55569Sbostic */
284*55569Sbostic 
285*55569Sbostic int
286*55569Sbostic BpfRead(rconn, doread)
287*55569Sbostic 	RMPCONN *rconn;
288*55569Sbostic 	int doread;
289*55569Sbostic {
290*55569Sbostic 	register int datlen, caplen, hdrlen;
291*55569Sbostic 	static u_char *bp = NULL, *ep = NULL;
292*55569Sbostic 	int cc;
293*55569Sbostic 
294*55569Sbostic 	/*
295*55569Sbostic 	 *  The read() may block, or it may return one or more packets.
296*55569Sbostic 	 *  We let the caller decide whether or not we can issue a read().
297*55569Sbostic 	 */
298*55569Sbostic 	if (doread) {
299*55569Sbostic 		if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) {
300*55569Sbostic 			syslog(LOG_ERR, "bpf: read: %m");
301*55569Sbostic 			return(0);
302*55569Sbostic 		} else {
303*55569Sbostic 			bp = BpfPkt;
304*55569Sbostic 			ep = BpfPkt + cc;
305*55569Sbostic 		}
306*55569Sbostic 	}
307*55569Sbostic 
308*55569Sbostic #define bhp ((struct bpf_hdr *)bp)
309*55569Sbostic 	/*
310*55569Sbostic 	 *  If there is a new packet in the buffer, stuff it into `rconn'
311*55569Sbostic 	 *  and return a success indication.
312*55569Sbostic 	 */
313*55569Sbostic 	if (bp < ep) {
314*55569Sbostic 		datlen = bhp->bh_datalen;
315*55569Sbostic 		caplen = bhp->bh_caplen;
316*55569Sbostic 		hdrlen = bhp->bh_hdrlen;
317*55569Sbostic 
318*55569Sbostic 		if (caplen != datlen)
319*55569Sbostic 			syslog(LOG_ERR,
320*55569Sbostic 			       "bpf: short packet dropped (%d of %d bytes)",
321*55569Sbostic 			       caplen, datlen);
322*55569Sbostic 		else if (caplen > sizeof(struct rmp_packet))
323*55569Sbostic 			syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)",
324*55569Sbostic 			       caplen);
325*55569Sbostic 		else {
326*55569Sbostic 			rconn->rmplen = caplen;
327*55569Sbostic 			bcopy((char *)&bhp->bh_tstamp, (char *)&rconn->tstamp,
328*55569Sbostic 			      sizeof(struct timeval));
329*55569Sbostic 			bcopy((char *)bp + hdrlen, (char *)&rconn->rmp, caplen);
330*55569Sbostic 		}
331*55569Sbostic 		bp += BPF_WORDALIGN(caplen + hdrlen);
332*55569Sbostic 		return(1);
333*55569Sbostic 	}
334*55569Sbostic #undef bhp
335*55569Sbostic 
336*55569Sbostic 	return(0);
337*55569Sbostic }
338*55569Sbostic 
339*55569Sbostic /*
340*55569Sbostic **  BpfWrite -- Write packet to BPF device.
341*55569Sbostic **
342*55569Sbostic **	Parameters:
343*55569Sbostic **		rconn - packet to send.
344*55569Sbostic **
345*55569Sbostic **	Returns:
346*55569Sbostic **		True if write succeeded, False otherwise.
347*55569Sbostic **
348*55569Sbostic **	Side Effects:
349*55569Sbostic **		None.
350*55569Sbostic */
351*55569Sbostic 
352*55569Sbostic BpfWrite(rconn)
353*55569Sbostic 	RMPCONN *rconn;
354*55569Sbostic {
355*55569Sbostic 	if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) {
356*55569Sbostic 		syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn));
357*55569Sbostic 		return(0);
358*55569Sbostic 	}
359*55569Sbostic 
360*55569Sbostic 	return(1);
361*55569Sbostic }
362*55569Sbostic 
363*55569Sbostic /*
364*55569Sbostic **  BpfOpen -- Close a BPF device.
365*55569Sbostic **
366*55569Sbostic **	Parameters:
367*55569Sbostic **		None.
368*55569Sbostic **
369*55569Sbostic **	Returns:
370*55569Sbostic **		Nothing.
371*55569Sbostic **
372*55569Sbostic **	Side Effects:
373*55569Sbostic **		None.
374*55569Sbostic */
375*55569Sbostic 
376*55569Sbostic BpfClose()
377*55569Sbostic {
378*55569Sbostic 	struct ifreq ifr;
379*55569Sbostic 
380*55569Sbostic 	if (BpfPkt != NULL) {
381*55569Sbostic 		free((char *)BpfPkt);
382*55569Sbostic 		BpfPkt = NULL;
383*55569Sbostic 	}
384*55569Sbostic 
385*55569Sbostic 	if (BpfFd == -1)
386*55569Sbostic 		return;
387*55569Sbostic 
388*55569Sbostic #ifdef MSG_EOR
389*55569Sbostic 	ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
390*55569Sbostic #endif
391*55569Sbostic 	ifr.ifr_addr.sa_family = AF_UNSPEC;
392*55569Sbostic 	bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN);
393*55569Sbostic 	if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0)
394*55569Sbostic 		(void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0);
395*55569Sbostic 
396*55569Sbostic 	(void) close(BpfFd);
397*55569Sbostic 	BpfFd = -1;
398*55569Sbostic }
399