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