1 /* 2 * Copyright (c) 1992 Regents of the University of California. 3 * Copyright (c) 1988, 1992 The University of Utah and the Center 4 * for Software Science (CSS). 5 * 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 5.1 (Berkeley) 07/23/92 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 5.1 (Berkeley) 07/23/92"; 23 #endif /* not lint */ 24 25 #include "defs.h" 26 27 #include <ctype.h> 28 #include <syslog.h> 29 #include <strings.h> 30 31 #include <sys/ioctl.h> 32 #include <sys/file.h> 33 #include <sys/errno.h> 34 35 #include <net/if.h> 36 #include <net/bpf.h> 37 38 #include "pathnames.h" 39 40 extern int errno; 41 42 static int BpfFd = -1; 43 static unsigned BpfLen = 0; 44 static u_char *BpfPkt = NULL; 45 46 /* 47 ** BpfOpen -- Open and initialize a BPF device. 48 ** 49 ** Parameters: 50 ** None. 51 ** 52 ** Returns: 53 ** File descriptor of opened BPF device (for select() etc). 54 ** 55 ** Side Effects: 56 ** If an error is encountered, the program terminates here. 57 */ 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 194 char * 195 BpfGetIntfName(errmsg) 196 char **errmsg; 197 { 198 struct ifreq ibuf[8], *ifrp, *ifend, *mp; 199 struct ifconf ifc; 200 int fd; 201 int minunit, n; 202 char *cp; 203 static char device[sizeof(ifrp->ifr_name)]; 204 static char errbuf[128] = "No Error!"; 205 206 if (errmsg != NULL) 207 *errmsg = errbuf; 208 209 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 210 (void) strcpy(errbuf, "bpf: socket: %m"); 211 return(NULL); 212 } 213 ifc.ifc_len = sizeof ibuf; 214 ifc.ifc_buf = (caddr_t)ibuf; 215 216 #ifdef OSIOCGIFCONF 217 if (ioctl(fd, OSIOCGIFCONF, (char *)&ifc) < 0 || 218 ifc.ifc_len < sizeof(struct ifreq)) { 219 (void) strcpy(errbuf, "bpf: ioctl(OSIOCGIFCONF): %m"); 220 return(NULL); 221 } 222 #else 223 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || 224 ifc.ifc_len < sizeof(struct ifreq)) { 225 (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m"); 226 return(NULL); 227 } 228 #endif 229 ifrp = ibuf; 230 ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); 231 232 mp = 0; 233 minunit = 666; 234 for (; ifrp < ifend; ++ifrp) { 235 if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) { 236 (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m"); 237 return(NULL); 238 } 239 240 /* 241 * If interface is down or this is the loopback interface, 242 * ignore it. 243 */ 244 if ((ifrp->ifr_flags & IFF_UP) == 0 || 245 #ifdef IFF_LOOPBACK 246 (ifrp->ifr_flags & IFF_LOOPBACK)) 247 #else 248 (strcmp(ifrp->ifr_name, "lo0") == 0)) 249 #endif 250 continue; 251 252 for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp) 253 ; 254 n = atoi(cp); 255 if (n < minunit) { 256 minunit = n; 257 mp = ifrp; 258 } 259 } 260 261 (void) close(fd); 262 if (mp == 0) { 263 (void) strcpy(errbuf, "bpf: no interfaces found"); 264 return(NULL); 265 } 266 267 (void) strcpy(device, mp->ifr_name); 268 return(device); 269 } 270 271 /* 272 ** BpfRead -- Read packets from a BPF device and fill in `rconn'. 273 ** 274 ** Parameters: 275 ** rconn - filled in with next packet. 276 ** doread - is True if we can issue a read() syscall. 277 ** 278 ** Returns: 279 ** True if `rconn' contains a new packet, False otherwise. 280 ** 281 ** Side Effects: 282 ** None. 283 */ 284 285 int 286 BpfRead(rconn, doread) 287 RMPCONN *rconn; 288 int doread; 289 { 290 register int datlen, caplen, hdrlen; 291 static u_char *bp = NULL, *ep = NULL; 292 int cc; 293 294 /* 295 * The read() may block, or it may return one or more packets. 296 * We let the caller decide whether or not we can issue a read(). 297 */ 298 if (doread) { 299 if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) { 300 syslog(LOG_ERR, "bpf: read: %m"); 301 return(0); 302 } else { 303 bp = BpfPkt; 304 ep = BpfPkt + cc; 305 } 306 } 307 308 #define bhp ((struct bpf_hdr *)bp) 309 /* 310 * If there is a new packet in the buffer, stuff it into `rconn' 311 * and return a success indication. 312 */ 313 if (bp < ep) { 314 datlen = bhp->bh_datalen; 315 caplen = bhp->bh_caplen; 316 hdrlen = bhp->bh_hdrlen; 317 318 if (caplen != datlen) 319 syslog(LOG_ERR, 320 "bpf: short packet dropped (%d of %d bytes)", 321 caplen, datlen); 322 else if (caplen > sizeof(struct rmp_packet)) 323 syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)", 324 caplen); 325 else { 326 rconn->rmplen = caplen; 327 bcopy((char *)&bhp->bh_tstamp, (char *)&rconn->tstamp, 328 sizeof(struct timeval)); 329 bcopy((char *)bp + hdrlen, (char *)&rconn->rmp, caplen); 330 } 331 bp += BPF_WORDALIGN(caplen + hdrlen); 332 return(1); 333 } 334 #undef bhp 335 336 return(0); 337 } 338 339 /* 340 ** BpfWrite -- Write packet to BPF device. 341 ** 342 ** Parameters: 343 ** rconn - packet to send. 344 ** 345 ** Returns: 346 ** True if write succeeded, False otherwise. 347 ** 348 ** Side Effects: 349 ** None. 350 */ 351 352 BpfWrite(rconn) 353 RMPCONN *rconn; 354 { 355 if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) { 356 syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn)); 357 return(0); 358 } 359 360 return(1); 361 } 362 363 /* 364 ** BpfOpen -- Close a BPF device. 365 ** 366 ** Parameters: 367 ** None. 368 ** 369 ** Returns: 370 ** Nothing. 371 ** 372 ** Side Effects: 373 ** None. 374 */ 375 376 BpfClose() 377 { 378 struct ifreq ifr; 379 380 if (BpfPkt != NULL) { 381 free((char *)BpfPkt); 382 BpfPkt = NULL; 383 } 384 385 if (BpfFd == -1) 386 return; 387 388 #ifdef MSG_EOR 389 ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; 390 #endif 391 ifr.ifr_addr.sa_family = AF_UNSPEC; 392 bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN); 393 if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0) 394 (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0); 395 396 (void) close(BpfFd); 397 BpfFd = -1; 398 } 399