1 /* 2 * Copyright (c) 1988, 1992 The University of Utah and the Center 3 * for Software Science (CSS). 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 * %sccs.include.redist.c% 14 * 15 * @(#)bpf.c 8.1 (Berkeley) 06/04/93 16 * 17 * Utah $Hdr: bpf.c 3.1 92/07/06$ 18 * Author: Jeff Forys, University of Utah CSS 19 */ 20 21 #ifndef lint 22 static char sccsid[] = "@(#)bpf.c 8.1 (Berkeley) 06/04/93"; 23 #endif /* not lint */ 24 25 #include <sys/param.h> 26 #include <sys/ioctl.h> 27 #include <sys/socket.h> 28 29 #include <net/if.h> 30 #include <net/bpf.h> 31 32 #include <ctype.h> 33 #include <errno.h> 34 #include <fcntl.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <syslog.h> 39 #include <unistd.h> 40 #include "defs.h" 41 #include "pathnames.h" 42 43 static int BpfFd = -1; 44 static unsigned BpfLen = 0; 45 static u_char *BpfPkt = NULL; 46 47 /* 48 ** BpfOpen -- Open and initialize a BPF device. 49 ** 50 ** Parameters: 51 ** None. 52 ** 53 ** Returns: 54 ** File descriptor of opened BPF device (for select() etc). 55 ** 56 ** Side Effects: 57 ** If an error is encountered, the program terminates here. 58 */ 59 int 60 BpfOpen() 61 { 62 struct ifreq ifr; 63 char bpfdev[32]; 64 int n = 0; 65 66 /* 67 * Open the first available BPF device. 68 */ 69 do { 70 (void) sprintf(bpfdev, _PATH_BPF, n++); 71 BpfFd = open(bpfdev, O_RDWR); 72 } while (BpfFd < 0 && (errno == EBUSY || errno == EPERM)); 73 74 if (BpfFd < 0) { 75 syslog(LOG_ERR, "bpf: no available devices: %m"); 76 Exit(0); 77 } 78 79 /* 80 * Set interface name for bpf device, get data link layer 81 * type and make sure it's type Ethernet. 82 */ 83 (void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name)); 84 if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) { 85 syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName); 86 Exit(0); 87 } 88 89 /* 90 * Make sure we are dealing with an Ethernet device. 91 */ 92 if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) { 93 syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m"); 94 Exit(0); 95 } 96 if (n != DLT_EN10MB) { 97 syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported", 98 IntfName, n); 99 Exit(0); 100 } 101 102 /* 103 * On read(), return packets immediately (do not buffer them). 104 */ 105 n = 1; 106 if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) { 107 syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m"); 108 Exit(0); 109 } 110 111 /* 112 * Try to enable the chip/driver's multicast address filter to 113 * grab our RMP address. If this fails, try promiscuous mode. 114 * If this fails, there's no way we are going to get any RMP 115 * packets so just exit here. 116 */ 117 #ifdef MSG_EOR 118 ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; 119 #endif 120 ifr.ifr_addr.sa_family = AF_UNSPEC; 121 bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN); 122 if (ioctl(BpfFd, SIOCADDMULTI, (caddr_t)&ifr) < 0) { 123 syslog(LOG_WARNING, 124 "bpf: can't add mcast addr (%m), setting promiscuous mode"); 125 126 if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) { 127 syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m"); 128 Exit(0); 129 } 130 } 131 132 /* 133 * Ask BPF how much buffer space it requires and allocate one. 134 */ 135 if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) { 136 syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m"); 137 Exit(0); 138 } 139 if (BpfPkt == NULL) 140 BpfPkt = (u_char *)malloc(BpfLen); 141 142 if (BpfPkt == NULL) { 143 syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)", 144 BpfLen); 145 Exit(0); 146 } 147 148 /* 149 * Write a little program to snarf RMP Boot packets and stuff 150 * it down BPF's throat (i.e. set up the packet filter). 151 */ 152 { 153 #define RMP ((struct rmp_packet *)0) 154 static struct bpf_insn bpf_insn[] = { 155 { BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap }, 156 { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP }, 157 { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl }, 158 { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP }, 159 { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap }, 160 { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP }, 161 { BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET }, 162 { BPF_RET|BPF_K, 0, 0, 0x0 } 163 }; 164 #undef RMP 165 static struct bpf_program bpf_pgm = { 166 sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn 167 }; 168 169 if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) { 170 syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m"); 171 Exit(0); 172 } 173 } 174 175 return(BpfFd); 176 } 177 178 /* 179 ** BPF GetIntfName -- Return the name of a network interface attached to 180 ** the system, or 0 if none can be found. The interface 181 ** must be configured up; the lowest unit number is 182 ** preferred; loopback is ignored. 183 ** 184 ** Parameters: 185 ** errmsg - if no network interface found, *errmsg explains why. 186 ** 187 ** Returns: 188 ** A (static) pointer to interface name, or NULL on error. 189 ** 190 ** Side Effects: 191 ** None. 192 */ 193 char * 194 BpfGetIntfName(errmsg) 195 char **errmsg; 196 { 197 struct ifreq ibuf[8], *ifrp, *ifend, *mp; 198 struct ifconf ifc; 199 int fd; 200 int minunit, n; 201 char *cp; 202 static char device[sizeof(ifrp->ifr_name)]; 203 static char errbuf[128] = "No Error!"; 204 205 if (errmsg != NULL) 206 *errmsg = errbuf; 207 208 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 209 (void) strcpy(errbuf, "bpf: socket: %m"); 210 return(NULL); 211 } 212 ifc.ifc_len = sizeof ibuf; 213 ifc.ifc_buf = (caddr_t)ibuf; 214 215 #ifdef OSIOCGIFCONF 216 if (ioctl(fd, OSIOCGIFCONF, (char *)&ifc) < 0 || 217 ifc.ifc_len < sizeof(struct ifreq)) { 218 (void) strcpy(errbuf, "bpf: ioctl(OSIOCGIFCONF): %m"); 219 return(NULL); 220 } 221 #else 222 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || 223 ifc.ifc_len < sizeof(struct ifreq)) { 224 (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m"); 225 return(NULL); 226 } 227 #endif 228 ifrp = ibuf; 229 ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); 230 231 mp = 0; 232 minunit = 666; 233 for (; ifrp < ifend; ++ifrp) { 234 if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) { 235 (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m"); 236 return(NULL); 237 } 238 239 /* 240 * If interface is down or this is the loopback interface, 241 * ignore it. 242 */ 243 if ((ifrp->ifr_flags & IFF_UP) == 0 || 244 #ifdef IFF_LOOPBACK 245 (ifrp->ifr_flags & IFF_LOOPBACK)) 246 #else 247 (strcmp(ifrp->ifr_name, "lo0") == 0)) 248 #endif 249 continue; 250 251 for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp) 252 ; 253 n = atoi(cp); 254 if (n < minunit) { 255 minunit = n; 256 mp = ifrp; 257 } 258 } 259 260 (void) close(fd); 261 if (mp == 0) { 262 (void) strcpy(errbuf, "bpf: no interfaces found"); 263 return(NULL); 264 } 265 266 (void) strcpy(device, mp->ifr_name); 267 return(device); 268 } 269 270 /* 271 ** BpfRead -- Read packets from a BPF device and fill in `rconn'. 272 ** 273 ** Parameters: 274 ** rconn - filled in with next packet. 275 ** doread - is True if we can issue a read() syscall. 276 ** 277 ** Returns: 278 ** True if `rconn' contains a new packet, False otherwise. 279 ** 280 ** Side Effects: 281 ** None. 282 */ 283 int 284 BpfRead(rconn, doread) 285 RMPCONN *rconn; 286 int doread; 287 { 288 register int datlen, caplen, hdrlen; 289 static u_char *bp = NULL, *ep = NULL; 290 int cc; 291 292 /* 293 * The read() may block, or it may return one or more packets. 294 * We let the caller decide whether or not we can issue a read(). 295 */ 296 if (doread) { 297 if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) { 298 syslog(LOG_ERR, "bpf: read: %m"); 299 return(0); 300 } else { 301 bp = BpfPkt; 302 ep = BpfPkt + cc; 303 } 304 } 305 306 #define bhp ((struct bpf_hdr *)bp) 307 /* 308 * If there is a new packet in the buffer, stuff it into `rconn' 309 * and return a success indication. 310 */ 311 if (bp < ep) { 312 datlen = bhp->bh_datalen; 313 caplen = bhp->bh_caplen; 314 hdrlen = bhp->bh_hdrlen; 315 316 if (caplen != datlen) 317 syslog(LOG_ERR, 318 "bpf: short packet dropped (%d of %d bytes)", 319 caplen, datlen); 320 else if (caplen > sizeof(struct rmp_packet)) 321 syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)", 322 caplen); 323 else { 324 rconn->rmplen = caplen; 325 bcopy((char *)&bhp->bh_tstamp, (char *)&rconn->tstamp, 326 sizeof(struct timeval)); 327 bcopy((char *)bp + hdrlen, (char *)&rconn->rmp, caplen); 328 } 329 bp += BPF_WORDALIGN(caplen + hdrlen); 330 return(1); 331 } 332 #undef bhp 333 334 return(0); 335 } 336 337 /* 338 ** BpfWrite -- Write packet to BPF device. 339 ** 340 ** Parameters: 341 ** rconn - packet to send. 342 ** 343 ** Returns: 344 ** True if write succeeded, False otherwise. 345 ** 346 ** Side Effects: 347 ** None. 348 */ 349 int 350 BpfWrite(rconn) 351 RMPCONN *rconn; 352 { 353 if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) { 354 syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn)); 355 return(0); 356 } 357 358 return(1); 359 } 360 361 /* 362 ** BpfClose -- Close a BPF device. 363 ** 364 ** Parameters: 365 ** None. 366 ** 367 ** Returns: 368 ** Nothing. 369 ** 370 ** Side Effects: 371 ** None. 372 */ 373 void 374 BpfClose() 375 { 376 struct ifreq ifr; 377 378 if (BpfPkt != NULL) { 379 free((char *)BpfPkt); 380 BpfPkt = NULL; 381 } 382 383 if (BpfFd == -1) 384 return; 385 386 #ifdef MSG_EOR 387 ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; 388 #endif 389 ifr.ifr_addr.sa_family = AF_UNSPEC; 390 bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN); 391 if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0) 392 (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0); 393 394 (void) close(BpfFd); 395 BpfFd = -1; 396 } 397