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