1 /* $NetBSD: bpf.c,v 1.16 2004/04/10 17:53:05 darrenr 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.16 2004/04/10 17:53:05 darrenr 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 u_int bufsize = 32768; 138 139 /* 140 * Open the first available BPF device. 141 */ 142 do { 143 (void) snprintf(bpfdev, sizeof(bpfdev), _PATH_BPF, n++); 144 BpfFd = open(bpfdev, O_RDWR); 145 } while (BpfFd < 0 && (errno == EBUSY || errno == EPERM)); 146 147 if (BpfFd < 0) { 148 syslog(LOG_ERR, "bpf: no available devices: %m"); 149 Exit(0); 150 } 151 152 if (ioctl(BpfFd, BIOCSBLEN, &bufsize) < 0) { 153 syslog(LOG_ERR, "bpf: ioctl(BIOCSBLEN,%d): %m", bufsize); 154 } 155 156 /* 157 * Set interface name for bpf device, get data link layer 158 * type and make sure it's type Ethernet. 159 */ 160 (void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name)); 161 if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) { 162 syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName); 163 Exit(0); 164 } 165 166 /* 167 * Make sure we are dealing with an Ethernet device. 168 */ 169 if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) { 170 syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m"); 171 Exit(0); 172 } 173 if (n != DLT_EN10MB) { 174 syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported", 175 IntfName, n); 176 Exit(0); 177 } 178 179 /* 180 * On read(), return packets immediately (do not buffer them). 181 */ 182 n = 1; 183 if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) { 184 syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m"); 185 Exit(0); 186 } 187 188 /* 189 * Try to enable the chip/driver's multicast address filter to 190 * grab our RMP address. If this fails, try promiscuous mode. 191 * If this fails, there's no way we are going to get any RMP 192 * packets so just exit here. 193 */ 194 #ifdef MSG_EOR 195 ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; 196 #endif 197 ifr.ifr_addr.sa_family = AF_UNSPEC; 198 memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0], 199 RMP_ADDRLEN); 200 if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) { 201 syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m"); 202 Exit(0); 203 } 204 205 /* 206 * Ask BPF how much buffer space it requires and allocate one. 207 */ 208 if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) { 209 syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m"); 210 Exit(0); 211 } 212 if (BpfPkt == NULL) 213 BpfPkt = (u_int8_t *)malloc(BpfLen); 214 215 if (BpfPkt == NULL) { 216 syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)", 217 BpfLen); 218 Exit(0); 219 } 220 221 /* 222 * Write a little program to snarf RMP Boot packets and stuff 223 * it down BPF's throat (i.e. set up the packet filter). 224 */ 225 { 226 #define RMP ((struct rmp_packet *)0) 227 static struct bpf_insn bpf_insn[] = { 228 { BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap }, 229 { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP }, 230 { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl }, 231 { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP }, 232 { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap }, 233 { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP }, 234 { BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET }, 235 { BPF_RET|BPF_K, 0, 0, 0x0 } 236 }; 237 #undef RMP 238 static struct bpf_program bpf_pgm = { 239 sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn 240 }; 241 242 if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) { 243 syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m"); 244 Exit(0); 245 } 246 } 247 248 return(BpfFd); 249 } 250 251 /* 252 ** BPF GetIntfName -- Return the name of a network interface attached to 253 ** the system, or 0 if none can be found. The interface 254 ** must be configured up; the lowest unit number is 255 ** preferred; loopback is ignored. 256 ** 257 ** Parameters: 258 ** errmsg - if no network interface found, *errmsg explains why. 259 ** 260 ** Returns: 261 ** A (static) pointer to interface name, or NULL on error. 262 ** 263 ** Side Effects: 264 ** None. 265 */ 266 char * 267 BpfGetIntfName(errmsg) 268 char **errmsg; 269 { 270 struct ifaddrs *ifap, *ifa, *p; 271 int minunit, n; 272 char *cp; 273 static char device[IFNAMSIZ + 1]; 274 static char errbuf[128] = "No Error!"; 275 276 if (errmsg != NULL) 277 *errmsg = errbuf; 278 279 if (getifaddrs(&ifap) != 0) { 280 (void) strlcpy(errbuf, "bpf: getifaddrs: %m", sizeof(errbuf)); 281 return(NULL); 282 } 283 284 p = NULL; 285 minunit = 666; 286 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 287 /* 288 * If interface is down or this is the loopback interface, 289 * ignore it. 290 */ 291 if ((ifa->ifa_flags & IFF_UP) == 0 || 292 #ifdef IFF_LOOPBACK 293 (ifa->ifa_flags & IFF_LOOPBACK)) 294 #else 295 (strcmp(ifa->ifa_name, "lo0") == 0)) 296 #endif 297 continue; 298 299 for (cp = ifa->ifa_name; !isdigit(*cp); ++cp) 300 ; 301 n = atoi(cp); 302 if (n < minunit) { 303 minunit = n; 304 p = ifa; 305 } 306 } 307 if (p == NULL) { 308 (void) strlcpy(errbuf, "bpf: no interfaces found", 309 sizeof(errbuf)); 310 freeifaddrs(ifap); 311 return(NULL); 312 } 313 314 (void) strlcpy(device, p->ifa_name, sizeof(device)); 315 freeifaddrs(ifap); 316 return(device); 317 } 318 319 /* 320 ** BpfRead -- Read packets from a BPF device and fill in `rconn'. 321 ** 322 ** Parameters: 323 ** rconn - filled in with next packet. 324 ** doread - is True if we can issue a read() syscall. 325 ** 326 ** Returns: 327 ** True if `rconn' contains a new packet, False otherwise. 328 ** 329 ** Side Effects: 330 ** None. 331 */ 332 int 333 BpfRead(rconn, doread) 334 RMPCONN *rconn; 335 int doread; 336 { 337 int datlen, caplen, hdrlen; 338 static u_int8_t *bp = NULL, *ep = NULL; 339 int cc; 340 341 /* 342 * The read() may block, or it may return one or more packets. 343 * We let the caller decide whether or not we can issue a read(). 344 */ 345 if (doread) { 346 if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) { 347 syslog(LOG_ERR, "bpf: read: %m"); 348 return(0); 349 } else { 350 bp = BpfPkt; 351 ep = BpfPkt + cc; 352 } 353 } 354 355 #define bhp ((struct bpf_hdr *)bp) 356 /* 357 * If there is a new packet in the buffer, stuff it into `rconn' 358 * and return a success indication. 359 */ 360 if (bp < ep) { 361 datlen = bhp->bh_datalen; 362 caplen = bhp->bh_caplen; 363 hdrlen = bhp->bh_hdrlen; 364 365 if (caplen != datlen) 366 syslog(LOG_ERR, 367 "bpf: short packet dropped (%d of %d bytes)", 368 caplen, datlen); 369 else if (caplen > sizeof(struct rmp_packet)) 370 syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)", 371 caplen); 372 else { 373 rconn->rmplen = caplen; 374 memmove((char *)&rconn->tstamp, (char *)&bhp->bh_tstamp, 375 sizeof(struct timeval)); 376 memmove((char *)&rconn->rmp, (char *)bp + hdrlen, 377 caplen); 378 } 379 bp += BPF_WORDALIGN(caplen + hdrlen); 380 return(1); 381 } 382 #undef bhp 383 384 return(0); 385 } 386 387 /* 388 ** BpfWrite -- Write packet to BPF device. 389 ** 390 ** Parameters: 391 ** rconn - packet to send. 392 ** 393 ** Returns: 394 ** True if write succeeded, False otherwise. 395 ** 396 ** Side Effects: 397 ** None. 398 */ 399 int 400 BpfWrite(rconn) 401 RMPCONN *rconn; 402 { 403 if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) { 404 syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn)); 405 return(0); 406 } 407 408 return(1); 409 } 410 411 /* 412 ** BpfClose -- Close a BPF device. 413 ** 414 ** Parameters: 415 ** None. 416 ** 417 ** Returns: 418 ** Nothing. 419 ** 420 ** Side Effects: 421 ** None. 422 */ 423 void 424 BpfClose() 425 { 426 struct ifreq ifr; 427 428 if (BpfPkt != NULL) { 429 free((char *)BpfPkt); 430 BpfPkt = NULL; 431 } 432 433 if (BpfFd == -1) 434 return; 435 436 #ifdef MSG_EOR 437 ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; 438 #endif 439 ifr.ifr_addr.sa_family = AF_UNSPEC; 440 memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0], 441 RMP_ADDRLEN); 442 if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0) 443 (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0); 444 445 (void) close(BpfFd); 446 BpfFd = -1; 447 } 448