1*e3711178Stsutsui /* $NetBSD: bpf.c,v 1.22 2022/09/03 07:45:08 tsutsui Exp $ */
2326b2259Sagc
3326b2259Sagc /*
49b6bd2d9Srmind * Copyright (c) 1988, 1992 The University of Utah and the Center
59b6bd2d9Srmind * for Software Science (CSS).
6326b2259Sagc * Copyright (c) 1992, 1993
7326b2259Sagc * The Regents of the University of California. All rights reserved.
8326b2259Sagc *
9326b2259Sagc * This code is derived from software contributed to Berkeley by
10326b2259Sagc * the Center for Software Science of the University of Utah Computer
11326b2259Sagc * Science Department. CSS requests users of this software to return
12326b2259Sagc * to css-dist@cs.utah.edu any improvements that they make and grant
13326b2259Sagc * CSS redistribution rights.
14326b2259Sagc *
15326b2259Sagc * Redistribution and use in source and binary forms, with or without
16326b2259Sagc * modification, are permitted provided that the following conditions
17326b2259Sagc * are met:
18326b2259Sagc * 1. Redistributions of source code must retain the above copyright
19326b2259Sagc * notice, this list of conditions and the following disclaimer.
20326b2259Sagc * 2. Redistributions in binary form must reproduce the above copyright
21326b2259Sagc * notice, this list of conditions and the following disclaimer in the
22326b2259Sagc * documentation and/or other materials provided with the distribution.
23326b2259Sagc * 3. Neither the name of the University nor the names of its contributors
24326b2259Sagc * may be used to endorse or promote products derived from this software
25326b2259Sagc * without specific prior written permission.
26326b2259Sagc *
27326b2259Sagc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28326b2259Sagc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29326b2259Sagc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30326b2259Sagc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31326b2259Sagc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32326b2259Sagc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33326b2259Sagc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34326b2259Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35326b2259Sagc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36326b2259Sagc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37326b2259Sagc * SUCH DAMAGE.
38326b2259Sagc *
39326b2259Sagc * from: @(#)bpf.c 8.1 (Berkeley) 6/4/93
40326b2259Sagc *
41326b2259Sagc * From: Utah Hdr: bpf.c 3.1 92/07/06
42326b2259Sagc * Author: Jeff Forys, University of Utah CSS
43326b2259Sagc */
446799ca39Sthorpej
454902da1cSthorpej #include <sys/cdefs.h>
46e05cab76Sbrezak #ifndef lint
474902da1cSthorpej #if 0
484902da1cSthorpej static char sccsid[] = "@(#)bpf.c 8.1 (Berkeley) 6/4/93";
494902da1cSthorpej #else
50*e3711178Stsutsui __RCSID("$NetBSD: bpf.c,v 1.22 2022/09/03 07:45:08 tsutsui Exp $");
514902da1cSthorpej #endif
52e05cab76Sbrezak #endif /* not lint */
53e05cab76Sbrezak
54e05cab76Sbrezak #include <sys/param.h>
55e05cab76Sbrezak #include <sys/ioctl.h>
56e05cab76Sbrezak #include <sys/socket.h>
57e05cab76Sbrezak
58e05cab76Sbrezak #include <net/if.h>
59e05cab76Sbrezak #include <net/bpf.h>
60e05cab76Sbrezak
61e05cab76Sbrezak #include <ctype.h>
62e05cab76Sbrezak #include <errno.h>
63e05cab76Sbrezak #include <fcntl.h>
64e05cab76Sbrezak #include <stdio.h>
65e05cab76Sbrezak #include <stdlib.h>
66e05cab76Sbrezak #include <string.h>
67e05cab76Sbrezak #include <syslog.h>
68fb5ec6aaSchristos #include <paths.h>
69e05cab76Sbrezak #include <unistd.h>
70e9c5139fSitojun #include <ifaddrs.h>
71e05cab76Sbrezak #include "defs.h"
72e05cab76Sbrezak #include "pathnames.h"
73e05cab76Sbrezak
74e05cab76Sbrezak static int BpfFd = -1;
75e05cab76Sbrezak static unsigned BpfLen = 0;
7631903d0eSthorpej static u_int8_t *BpfPkt = NULL;
77e05cab76Sbrezak
78e05cab76Sbrezak /*
79e05cab76Sbrezak ** BpfOpen -- Open and initialize a BPF device.
80e05cab76Sbrezak **
81e05cab76Sbrezak ** Parameters:
82e05cab76Sbrezak ** None.
83e05cab76Sbrezak **
84e05cab76Sbrezak ** Returns:
85e05cab76Sbrezak ** File descriptor of opened BPF device (for select() etc).
86e05cab76Sbrezak **
87e05cab76Sbrezak ** Side Effects:
88e05cab76Sbrezak ** If an error is encountered, the program terminates here.
89e05cab76Sbrezak */
90e05cab76Sbrezak int
BpfOpen(void)91*e3711178Stsutsui BpfOpen(void)
92e05cab76Sbrezak {
93e05cab76Sbrezak struct ifreq ifr;
94221fa572Sdarrenr u_int bufsize = 32768;
95fb5ec6aaSchristos int n;
96e05cab76Sbrezak
97fb5ec6aaSchristos BpfFd = open(_PATH_BPF, O_RDWR);
98e05cab76Sbrezak if (BpfFd < 0) {
99e05cab76Sbrezak syslog(LOG_ERR, "bpf: no available devices: %m");
100e05cab76Sbrezak Exit(0);
101e05cab76Sbrezak }
102e05cab76Sbrezak
103221fa572Sdarrenr if (ioctl(BpfFd, BIOCSBLEN, &bufsize) < 0) {
104221fa572Sdarrenr syslog(LOG_ERR, "bpf: ioctl(BIOCSBLEN,%d): %m", bufsize);
105221fa572Sdarrenr }
106221fa572Sdarrenr
107e05cab76Sbrezak /*
108e05cab76Sbrezak * Set interface name for bpf device, get data link layer
109e05cab76Sbrezak * type and make sure it's type Ethernet.
110e05cab76Sbrezak */
111e05cab76Sbrezak (void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name));
112e05cab76Sbrezak if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) {
113e05cab76Sbrezak syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName);
114e05cab76Sbrezak Exit(0);
115e05cab76Sbrezak }
116e05cab76Sbrezak
117e05cab76Sbrezak /*
118e05cab76Sbrezak * Make sure we are dealing with an Ethernet device.
119e05cab76Sbrezak */
120e05cab76Sbrezak if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) {
121e05cab76Sbrezak syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m");
122e05cab76Sbrezak Exit(0);
123e05cab76Sbrezak }
124e05cab76Sbrezak if (n != DLT_EN10MB) {
125e05cab76Sbrezak syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported",
126e05cab76Sbrezak IntfName, n);
127e05cab76Sbrezak Exit(0);
128e05cab76Sbrezak }
129e05cab76Sbrezak
130e05cab76Sbrezak /*
131e05cab76Sbrezak * On read(), return packets immediately (do not buffer them).
132e05cab76Sbrezak */
133e05cab76Sbrezak n = 1;
134e05cab76Sbrezak if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) {
135e05cab76Sbrezak syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m");
136e05cab76Sbrezak Exit(0);
137e05cab76Sbrezak }
138e05cab76Sbrezak
139e05cab76Sbrezak /*
140e05cab76Sbrezak * Try to enable the chip/driver's multicast address filter to
141e05cab76Sbrezak * grab our RMP address. If this fails, try promiscuous mode.
142e05cab76Sbrezak * If this fails, there's no way we are going to get any RMP
143e05cab76Sbrezak * packets so just exit here.
144e05cab76Sbrezak */
145e05cab76Sbrezak #ifdef MSG_EOR
146e05cab76Sbrezak ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
147e05cab76Sbrezak #endif
148e05cab76Sbrezak ifr.ifr_addr.sa_family = AF_UNSPEC;
149dd30ff55Slukem memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0],
150dd30ff55Slukem RMP_ADDRLEN);
151e05cab76Sbrezak if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) {
152e05cab76Sbrezak syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m");
153e05cab76Sbrezak Exit(0);
154e05cab76Sbrezak }
155e05cab76Sbrezak
156e05cab76Sbrezak /*
157e05cab76Sbrezak * Ask BPF how much buffer space it requires and allocate one.
158e05cab76Sbrezak */
159e05cab76Sbrezak if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) {
160e05cab76Sbrezak syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m");
161e05cab76Sbrezak Exit(0);
162e05cab76Sbrezak }
163e05cab76Sbrezak if (BpfPkt == NULL)
16431903d0eSthorpej BpfPkt = (u_int8_t *)malloc(BpfLen);
165e05cab76Sbrezak
166e05cab76Sbrezak if (BpfPkt == NULL) {
167e05cab76Sbrezak syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)",
168e05cab76Sbrezak BpfLen);
169e05cab76Sbrezak Exit(0);
170e05cab76Sbrezak }
171e05cab76Sbrezak
172e05cab76Sbrezak /*
173e05cab76Sbrezak * Write a little program to snarf RMP Boot packets and stuff
174e05cab76Sbrezak * it down BPF's throat (i.e. set up the packet filter).
175e05cab76Sbrezak */
176e05cab76Sbrezak {
177e05cab76Sbrezak #define RMP ((struct rmp_packet *)0)
178e05cab76Sbrezak static struct bpf_insn bpf_insn[] = {
179e05cab76Sbrezak { BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap },
180e05cab76Sbrezak { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP },
181e05cab76Sbrezak { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl },
182e05cab76Sbrezak { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP },
183e05cab76Sbrezak { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap },
184e05cab76Sbrezak { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP },
185e05cab76Sbrezak { BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET },
186e05cab76Sbrezak { BPF_RET|BPF_K, 0, 0, 0x0 }
187e05cab76Sbrezak };
188e05cab76Sbrezak #undef RMP
189e05cab76Sbrezak static struct bpf_program bpf_pgm = {
190e05cab76Sbrezak sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn
191e05cab76Sbrezak };
192e05cab76Sbrezak
193e05cab76Sbrezak if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) {
194e05cab76Sbrezak syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m");
195e05cab76Sbrezak Exit(0);
196e05cab76Sbrezak }
197e05cab76Sbrezak }
198e05cab76Sbrezak
199e05cab76Sbrezak return(BpfFd);
200e05cab76Sbrezak }
201e05cab76Sbrezak
202e05cab76Sbrezak /*
203e05cab76Sbrezak ** BPF GetIntfName -- Return the name of a network interface attached to
204e05cab76Sbrezak ** the system, or 0 if none can be found. The interface
205e05cab76Sbrezak ** must be configured up; the lowest unit number is
206e05cab76Sbrezak ** preferred; loopback is ignored.
207e05cab76Sbrezak **
208e05cab76Sbrezak ** Parameters:
209e05cab76Sbrezak ** errmsg - if no network interface found, *errmsg explains why.
210e05cab76Sbrezak **
211e05cab76Sbrezak ** Returns:
212e05cab76Sbrezak ** A (static) pointer to interface name, or NULL on error.
213e05cab76Sbrezak **
214e05cab76Sbrezak ** Side Effects:
215e05cab76Sbrezak ** None.
216e05cab76Sbrezak */
217e05cab76Sbrezak char *
BpfGetIntfName(char ** errmsg)218421949a3Ssevan BpfGetIntfName(char **errmsg)
219e05cab76Sbrezak {
220e9c5139fSitojun struct ifaddrs *ifap, *ifa, *p;
221e9c5139fSitojun int minunit, n;
222e9c5139fSitojun char *cp;
223e9c5139fSitojun static char device[IFNAMSIZ + 1];
224e9c5139fSitojun static char errbuf[128] = "No Error!";
225e9c5139fSitojun
2269b7718e1Slukem if (errmsg != NULL)
2279b7718e1Slukem *errmsg = errbuf;
2289b7718e1Slukem
229e9c5139fSitojun if (getifaddrs(&ifap) != 0) {
2307bb0ef55Sitojun (void) strlcpy(errbuf, "bpf: getifaddrs: %m", sizeof(errbuf));
231e9c5139fSitojun return(NULL);
232e9c5139fSitojun }
233e9c5139fSitojun
234e9c5139fSitojun p = NULL;
235e9c5139fSitojun minunit = 666;
236e9c5139fSitojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
237e9c5139fSitojun /*
238e9c5139fSitojun * If interface is down or this is the loopback interface,
239e9c5139fSitojun * ignore it.
240e9c5139fSitojun */
241e9c5139fSitojun if ((ifa->ifa_flags & IFF_UP) == 0 ||
242e9c5139fSitojun #ifdef IFF_LOOPBACK
243e9c5139fSitojun (ifa->ifa_flags & IFF_LOOPBACK))
244e9c5139fSitojun #else
245e9c5139fSitojun (strcmp(ifa->ifa_name, "lo0") == 0))
246e9c5139fSitojun #endif
247e9c5139fSitojun continue;
248e9c5139fSitojun
249e2f49bd9Sdsl for (cp = ifa->ifa_name; !isdigit((unsigned char)*cp); ++cp)
250e9c5139fSitojun ;
251e9c5139fSitojun n = atoi(cp);
252e9c5139fSitojun if (n < minunit) {
253e9c5139fSitojun minunit = n;
254e9c5139fSitojun p = ifa;
255e9c5139fSitojun }
256e9c5139fSitojun }
257e9c5139fSitojun if (p == NULL) {
2587bb0ef55Sitojun (void) strlcpy(errbuf, "bpf: no interfaces found",
2597bb0ef55Sitojun sizeof(errbuf));
260e9c5139fSitojun freeifaddrs(ifap);
261e9c5139fSitojun return(NULL);
262e9c5139fSitojun }
263e9c5139fSitojun
2647f5c6fbfSitojun (void) strlcpy(device, p->ifa_name, sizeof(device));
265e9c5139fSitojun freeifaddrs(ifap);
266e9c5139fSitojun return(device);
267e05cab76Sbrezak }
268e05cab76Sbrezak
269e05cab76Sbrezak /*
270e05cab76Sbrezak ** BpfRead -- Read packets from a BPF device and fill in `rconn'.
271e05cab76Sbrezak **
272e05cab76Sbrezak ** Parameters:
273e05cab76Sbrezak ** rconn - filled in with next packet.
274e05cab76Sbrezak ** doread - is True if we can issue a read() syscall.
275e05cab76Sbrezak **
276e05cab76Sbrezak ** Returns:
277e05cab76Sbrezak ** True if `rconn' contains a new packet, False otherwise.
278e05cab76Sbrezak **
279e05cab76Sbrezak ** Side Effects:
280e05cab76Sbrezak ** None.
281e05cab76Sbrezak */
282e05cab76Sbrezak int
BpfRead(RMPCONN * rconn,int doread)283421949a3Ssevan BpfRead(RMPCONN *rconn, int doread)
284e05cab76Sbrezak {
285dd30ff55Slukem int datlen, caplen, hdrlen;
28631903d0eSthorpej static u_int8_t *bp = NULL, *ep = NULL;
287e05cab76Sbrezak int cc;
288e05cab76Sbrezak
289e05cab76Sbrezak /*
290e05cab76Sbrezak * The read() may block, or it may return one or more packets.
291e05cab76Sbrezak * We let the caller decide whether or not we can issue a read().
292e05cab76Sbrezak */
293e05cab76Sbrezak if (doread) {
294e05cab76Sbrezak if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) {
295e05cab76Sbrezak syslog(LOG_ERR, "bpf: read: %m");
296e05cab76Sbrezak return(0);
297e05cab76Sbrezak } else {
298e05cab76Sbrezak bp = BpfPkt;
299e05cab76Sbrezak ep = BpfPkt + cc;
300e05cab76Sbrezak }
301e05cab76Sbrezak }
302e05cab76Sbrezak
303e05cab76Sbrezak #define bhp ((struct bpf_hdr *)bp)
304e05cab76Sbrezak /*
305e05cab76Sbrezak * If there is a new packet in the buffer, stuff it into `rconn'
306e05cab76Sbrezak * and return a success indication.
307e05cab76Sbrezak */
308e05cab76Sbrezak if (bp < ep) {
309e05cab76Sbrezak datlen = bhp->bh_datalen;
310e05cab76Sbrezak caplen = bhp->bh_caplen;
311e05cab76Sbrezak hdrlen = bhp->bh_hdrlen;
312e05cab76Sbrezak
313e05cab76Sbrezak if (caplen != datlen)
314e05cab76Sbrezak syslog(LOG_ERR,
315e05cab76Sbrezak "bpf: short packet dropped (%d of %d bytes)",
316e05cab76Sbrezak caplen, datlen);
317178a598dSlukem else if (caplen > (int)sizeof(struct rmp_packet))
318e05cab76Sbrezak syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)",
319e05cab76Sbrezak caplen);
320e05cab76Sbrezak else {
321507ba824Sthorpej rconn->rmplen = caplen;
322dd30ff55Slukem memmove((char *)&rconn->tstamp, (char *)&bhp->bh_tstamp,
323e05cab76Sbrezak sizeof(struct timeval));
324dd30ff55Slukem memmove((char *)&rconn->rmp, (char *)bp + hdrlen,
325dd30ff55Slukem caplen);
326e05cab76Sbrezak }
327e05cab76Sbrezak bp += BPF_WORDALIGN(caplen + hdrlen);
328e05cab76Sbrezak return(1);
329e05cab76Sbrezak }
330e05cab76Sbrezak #undef bhp
331e05cab76Sbrezak
332e05cab76Sbrezak return(0);
333e05cab76Sbrezak }
334e05cab76Sbrezak
335e05cab76Sbrezak /*
336e05cab76Sbrezak ** BpfWrite -- Write packet to BPF device.
337e05cab76Sbrezak **
338e05cab76Sbrezak ** Parameters:
339e05cab76Sbrezak ** rconn - packet to send.
340e05cab76Sbrezak **
341e05cab76Sbrezak ** Returns:
342e05cab76Sbrezak ** True if write succeeded, False otherwise.
343e05cab76Sbrezak **
344e05cab76Sbrezak ** Side Effects:
345e05cab76Sbrezak ** None.
346e05cab76Sbrezak */
347e05cab76Sbrezak int
BpfWrite(RMPCONN * rconn)348421949a3Ssevan BpfWrite(RMPCONN *rconn)
349e05cab76Sbrezak {
350507ba824Sthorpej if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) {
351e05cab76Sbrezak syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn));
352e05cab76Sbrezak return(0);
353e05cab76Sbrezak }
354e05cab76Sbrezak
355e05cab76Sbrezak return(1);
356e05cab76Sbrezak }
357e05cab76Sbrezak
358e05cab76Sbrezak /*
359e05cab76Sbrezak ** BpfClose -- Close a BPF device.
360e05cab76Sbrezak **
361e05cab76Sbrezak ** Parameters:
362e05cab76Sbrezak ** None.
363e05cab76Sbrezak **
364e05cab76Sbrezak ** Returns:
365e05cab76Sbrezak ** Nothing.
366e05cab76Sbrezak **
367e05cab76Sbrezak ** Side Effects:
368e05cab76Sbrezak ** None.
369e05cab76Sbrezak */
370e05cab76Sbrezak void
BpfClose(void)371*e3711178Stsutsui BpfClose(void)
372e05cab76Sbrezak {
373e05cab76Sbrezak struct ifreq ifr;
374e05cab76Sbrezak
375e05cab76Sbrezak if (BpfPkt != NULL) {
376e05cab76Sbrezak free((char *)BpfPkt);
377e05cab76Sbrezak BpfPkt = NULL;
378e05cab76Sbrezak }
379e05cab76Sbrezak
380e05cab76Sbrezak if (BpfFd == -1)
381e05cab76Sbrezak return;
382e05cab76Sbrezak
383e05cab76Sbrezak #ifdef MSG_EOR
384e05cab76Sbrezak ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
385e05cab76Sbrezak #endif
386e05cab76Sbrezak ifr.ifr_addr.sa_family = AF_UNSPEC;
387dd30ff55Slukem memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0],
388dd30ff55Slukem RMP_ADDRLEN);
389e05cab76Sbrezak if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0)
390e05cab76Sbrezak (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0);
391e05cab76Sbrezak
392e05cab76Sbrezak (void) close(BpfFd);
393e05cab76Sbrezak BpfFd = -1;
394e05cab76Sbrezak }
395