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