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