155569Sbostic /* 255569Sbostic * Copyright (c) 1992 Regents of the University of California. 355569Sbostic * Copyright (c) 1988, 1992 The University of Utah and the Center 455569Sbostic * for Software Science (CSS). 555569Sbostic * All rights reserved. 655569Sbostic * 755569Sbostic * This code is derived from software contributed to Berkeley by 855569Sbostic * the Center for Software Science of the University of Utah Computer 955569Sbostic * Science Department. CSS requests users of this software to return 1055569Sbostic * to css-dist@cs.utah.edu any improvements that they make and grant 1155569Sbostic * CSS redistribution rights. 1255569Sbostic * 1355569Sbostic * %sccs.include.redist.c% 1455569Sbostic * 15*55600Sbostic * @(#)bpf.c 5.2 (Berkeley) 07/23/92 1655569Sbostic * 1755569Sbostic * Utah $Hdr: bpf.c 3.1 92/07/06$ 1855569Sbostic * Author: Jeff Forys, University of Utah CSS 1955569Sbostic */ 2055569Sbostic 2155569Sbostic #ifndef lint 22*55600Sbostic static char sccsid[] = "@(#)bpf.c 5.2 (Berkeley) 07/23/92"; 2355569Sbostic #endif /* not lint */ 2455569Sbostic 25*55600Sbostic #include <sys/param.h> 2655569Sbostic #include <sys/ioctl.h> 27*55600Sbostic #include <sys/socket.h> 2855569Sbostic 2955569Sbostic #include <net/if.h> 3055569Sbostic #include <net/bpf.h> 3155569Sbostic 32*55600Sbostic #include <ctype.h> 33*55600Sbostic #include <errno.h> 34*55600Sbostic #include <fcntl.h> 35*55600Sbostic #include <stdio.h> 36*55600Sbostic #include <stdlib.h> 37*55600Sbostic #include <string.h> 38*55600Sbostic #include <syslog.h> 39*55600Sbostic #include <unistd.h> 40*55600Sbostic #include "defs.h" 4155569Sbostic #include "pathnames.h" 4255569Sbostic 4355569Sbostic static int BpfFd = -1; 4455569Sbostic static unsigned BpfLen = 0; 4555569Sbostic static u_char *BpfPkt = NULL; 4655569Sbostic 4755569Sbostic /* 4855569Sbostic ** BpfOpen -- Open and initialize a BPF device. 4955569Sbostic ** 5055569Sbostic ** Parameters: 5155569Sbostic ** None. 5255569Sbostic ** 5355569Sbostic ** Returns: 5455569Sbostic ** File descriptor of opened BPF device (for select() etc). 5555569Sbostic ** 5655569Sbostic ** Side Effects: 5755569Sbostic ** If an error is encountered, the program terminates here. 5855569Sbostic */ 5955569Sbostic int 6055569Sbostic BpfOpen() 6155569Sbostic { 6255569Sbostic struct ifreq ifr; 6355569Sbostic char bpfdev[32]; 6455569Sbostic int n = 0; 6555569Sbostic 6655569Sbostic /* 6755569Sbostic * Open the first available BPF device. 6855569Sbostic */ 6955569Sbostic do { 7055569Sbostic (void) sprintf(bpfdev, _PATH_BPF, n++); 7155569Sbostic BpfFd = open(bpfdev, O_RDWR); 7255569Sbostic } while (BpfFd < 0 && (errno == EBUSY || errno == EPERM)); 7355569Sbostic 7455569Sbostic if (BpfFd < 0) { 7555569Sbostic syslog(LOG_ERR, "bpf: no available devices: %m"); 7655569Sbostic Exit(0); 7755569Sbostic } 7855569Sbostic 7955569Sbostic /* 8055569Sbostic * Set interface name for bpf device, get data link layer 8155569Sbostic * type and make sure it's type Ethernet. 8255569Sbostic */ 8355569Sbostic (void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name)); 8455569Sbostic if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) { 8555569Sbostic syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName); 8655569Sbostic Exit(0); 8755569Sbostic } 8855569Sbostic 8955569Sbostic /* 9055569Sbostic * Make sure we are dealing with an Ethernet device. 9155569Sbostic */ 9255569Sbostic if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) { 9355569Sbostic syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m"); 9455569Sbostic Exit(0); 9555569Sbostic } 9655569Sbostic if (n != DLT_EN10MB) { 9755569Sbostic syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported", 9855569Sbostic IntfName, n); 9955569Sbostic Exit(0); 10055569Sbostic } 10155569Sbostic 10255569Sbostic /* 10355569Sbostic * On read(), return packets immediately (do not buffer them). 10455569Sbostic */ 10555569Sbostic n = 1; 10655569Sbostic if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) { 10755569Sbostic syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m"); 10855569Sbostic Exit(0); 10955569Sbostic } 11055569Sbostic 11155569Sbostic /* 11255569Sbostic * Try to enable the chip/driver's multicast address filter to 11355569Sbostic * grab our RMP address. If this fails, try promiscuous mode. 11455569Sbostic * If this fails, there's no way we are going to get any RMP 11555569Sbostic * packets so just exit here. 11655569Sbostic */ 11755569Sbostic #ifdef MSG_EOR 11855569Sbostic ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; 11955569Sbostic #endif 12055569Sbostic ifr.ifr_addr.sa_family = AF_UNSPEC; 12155569Sbostic bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN); 12255569Sbostic if (ioctl(BpfFd, SIOCADDMULTI, (caddr_t)&ifr) < 0) { 12355569Sbostic syslog(LOG_WARNING, 12455569Sbostic "bpf: can't add mcast addr (%m), setting promiscuous mode"); 12555569Sbostic 12655569Sbostic if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) { 12755569Sbostic syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m"); 12855569Sbostic Exit(0); 12955569Sbostic } 13055569Sbostic } 13155569Sbostic 13255569Sbostic /* 13355569Sbostic * Ask BPF how much buffer space it requires and allocate one. 13455569Sbostic */ 13555569Sbostic if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) { 13655569Sbostic syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m"); 13755569Sbostic Exit(0); 13855569Sbostic } 13955569Sbostic if (BpfPkt == NULL) 14055569Sbostic BpfPkt = (u_char *)malloc(BpfLen); 14155569Sbostic 14255569Sbostic if (BpfPkt == NULL) { 14355569Sbostic syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)", 14455569Sbostic BpfLen); 14555569Sbostic Exit(0); 14655569Sbostic } 14755569Sbostic 14855569Sbostic /* 14955569Sbostic * Write a little program to snarf RMP Boot packets and stuff 15055569Sbostic * it down BPF's throat (i.e. set up the packet filter). 15155569Sbostic */ 15255569Sbostic { 15355569Sbostic #define RMP ((struct rmp_packet *)0) 15455569Sbostic static struct bpf_insn bpf_insn[] = { 15555569Sbostic { BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap }, 15655569Sbostic { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP }, 15755569Sbostic { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl }, 15855569Sbostic { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP }, 15955569Sbostic { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap }, 16055569Sbostic { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP }, 16155569Sbostic { BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET }, 16255569Sbostic { BPF_RET|BPF_K, 0, 0, 0x0 } 16355569Sbostic }; 16455569Sbostic #undef RMP 16555569Sbostic static struct bpf_program bpf_pgm = { 16655569Sbostic sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn 16755569Sbostic }; 16855569Sbostic 16955569Sbostic if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) { 17055569Sbostic syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m"); 17155569Sbostic Exit(0); 17255569Sbostic } 17355569Sbostic } 17455569Sbostic 17555569Sbostic return(BpfFd); 17655569Sbostic } 17755569Sbostic 17855569Sbostic /* 17955569Sbostic ** BPF GetIntfName -- Return the name of a network interface attached to 18055569Sbostic ** the system, or 0 if none can be found. The interface 18155569Sbostic ** must be configured up; the lowest unit number is 18255569Sbostic ** preferred; loopback is ignored. 18355569Sbostic ** 18455569Sbostic ** Parameters: 18555569Sbostic ** errmsg - if no network interface found, *errmsg explains why. 18655569Sbostic ** 18755569Sbostic ** Returns: 18855569Sbostic ** A (static) pointer to interface name, or NULL on error. 18955569Sbostic ** 19055569Sbostic ** Side Effects: 19155569Sbostic ** None. 19255569Sbostic */ 19355569Sbostic char * 19455569Sbostic BpfGetIntfName(errmsg) 19555569Sbostic char **errmsg; 19655569Sbostic { 19755569Sbostic struct ifreq ibuf[8], *ifrp, *ifend, *mp; 19855569Sbostic struct ifconf ifc; 19955569Sbostic int fd; 20055569Sbostic int minunit, n; 20155569Sbostic char *cp; 20255569Sbostic static char device[sizeof(ifrp->ifr_name)]; 20355569Sbostic static char errbuf[128] = "No Error!"; 20455569Sbostic 20555569Sbostic if (errmsg != NULL) 20655569Sbostic *errmsg = errbuf; 20755569Sbostic 20855569Sbostic if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 20955569Sbostic (void) strcpy(errbuf, "bpf: socket: %m"); 21055569Sbostic return(NULL); 21155569Sbostic } 21255569Sbostic ifc.ifc_len = sizeof ibuf; 21355569Sbostic ifc.ifc_buf = (caddr_t)ibuf; 21455569Sbostic 21555569Sbostic #ifdef OSIOCGIFCONF 21655569Sbostic if (ioctl(fd, OSIOCGIFCONF, (char *)&ifc) < 0 || 21755569Sbostic ifc.ifc_len < sizeof(struct ifreq)) { 21855569Sbostic (void) strcpy(errbuf, "bpf: ioctl(OSIOCGIFCONF): %m"); 21955569Sbostic return(NULL); 22055569Sbostic } 22155569Sbostic #else 22255569Sbostic if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || 22355569Sbostic ifc.ifc_len < sizeof(struct ifreq)) { 22455569Sbostic (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m"); 22555569Sbostic return(NULL); 22655569Sbostic } 22755569Sbostic #endif 22855569Sbostic ifrp = ibuf; 22955569Sbostic ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); 23055569Sbostic 23155569Sbostic mp = 0; 23255569Sbostic minunit = 666; 23355569Sbostic for (; ifrp < ifend; ++ifrp) { 23455569Sbostic if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) { 23555569Sbostic (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m"); 23655569Sbostic return(NULL); 23755569Sbostic } 23855569Sbostic 23955569Sbostic /* 24055569Sbostic * If interface is down or this is the loopback interface, 24155569Sbostic * ignore it. 24255569Sbostic */ 24355569Sbostic if ((ifrp->ifr_flags & IFF_UP) == 0 || 24455569Sbostic #ifdef IFF_LOOPBACK 24555569Sbostic (ifrp->ifr_flags & IFF_LOOPBACK)) 24655569Sbostic #else 24755569Sbostic (strcmp(ifrp->ifr_name, "lo0") == 0)) 24855569Sbostic #endif 24955569Sbostic continue; 25055569Sbostic 25155569Sbostic for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp) 25255569Sbostic ; 25355569Sbostic n = atoi(cp); 25455569Sbostic if (n < minunit) { 25555569Sbostic minunit = n; 25655569Sbostic mp = ifrp; 25755569Sbostic } 25855569Sbostic } 25955569Sbostic 26055569Sbostic (void) close(fd); 26155569Sbostic if (mp == 0) { 26255569Sbostic (void) strcpy(errbuf, "bpf: no interfaces found"); 26355569Sbostic return(NULL); 26455569Sbostic } 26555569Sbostic 26655569Sbostic (void) strcpy(device, mp->ifr_name); 26755569Sbostic return(device); 26855569Sbostic } 26955569Sbostic 27055569Sbostic /* 27155569Sbostic ** BpfRead -- Read packets from a BPF device and fill in `rconn'. 27255569Sbostic ** 27355569Sbostic ** Parameters: 27455569Sbostic ** rconn - filled in with next packet. 27555569Sbostic ** doread - is True if we can issue a read() syscall. 27655569Sbostic ** 27755569Sbostic ** Returns: 27855569Sbostic ** True if `rconn' contains a new packet, False otherwise. 27955569Sbostic ** 28055569Sbostic ** Side Effects: 28155569Sbostic ** None. 28255569Sbostic */ 28355569Sbostic int 28455569Sbostic BpfRead(rconn, doread) 28555569Sbostic RMPCONN *rconn; 28655569Sbostic int doread; 28755569Sbostic { 28855569Sbostic register int datlen, caplen, hdrlen; 28955569Sbostic static u_char *bp = NULL, *ep = NULL; 29055569Sbostic int cc; 29155569Sbostic 29255569Sbostic /* 29355569Sbostic * The read() may block, or it may return one or more packets. 29455569Sbostic * We let the caller decide whether or not we can issue a read(). 29555569Sbostic */ 29655569Sbostic if (doread) { 29755569Sbostic if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) { 29855569Sbostic syslog(LOG_ERR, "bpf: read: %m"); 29955569Sbostic return(0); 30055569Sbostic } else { 30155569Sbostic bp = BpfPkt; 30255569Sbostic ep = BpfPkt + cc; 30355569Sbostic } 30455569Sbostic } 30555569Sbostic 30655569Sbostic #define bhp ((struct bpf_hdr *)bp) 30755569Sbostic /* 30855569Sbostic * If there is a new packet in the buffer, stuff it into `rconn' 30955569Sbostic * and return a success indication. 31055569Sbostic */ 31155569Sbostic if (bp < ep) { 31255569Sbostic datlen = bhp->bh_datalen; 31355569Sbostic caplen = bhp->bh_caplen; 31455569Sbostic hdrlen = bhp->bh_hdrlen; 31555569Sbostic 31655569Sbostic if (caplen != datlen) 31755569Sbostic syslog(LOG_ERR, 31855569Sbostic "bpf: short packet dropped (%d of %d bytes)", 31955569Sbostic caplen, datlen); 32055569Sbostic else if (caplen > sizeof(struct rmp_packet)) 32155569Sbostic syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)", 32255569Sbostic caplen); 32355569Sbostic else { 32455569Sbostic rconn->rmplen = caplen; 32555569Sbostic bcopy((char *)&bhp->bh_tstamp, (char *)&rconn->tstamp, 32655569Sbostic sizeof(struct timeval)); 32755569Sbostic bcopy((char *)bp + hdrlen, (char *)&rconn->rmp, caplen); 32855569Sbostic } 32955569Sbostic bp += BPF_WORDALIGN(caplen + hdrlen); 33055569Sbostic return(1); 33155569Sbostic } 33255569Sbostic #undef bhp 33355569Sbostic 33455569Sbostic return(0); 33555569Sbostic } 33655569Sbostic 33755569Sbostic /* 33855569Sbostic ** BpfWrite -- Write packet to BPF device. 33955569Sbostic ** 34055569Sbostic ** Parameters: 34155569Sbostic ** rconn - packet to send. 34255569Sbostic ** 34355569Sbostic ** Returns: 34455569Sbostic ** True if write succeeded, False otherwise. 34555569Sbostic ** 34655569Sbostic ** Side Effects: 34755569Sbostic ** None. 34855569Sbostic */ 349*55600Sbostic int 35055569Sbostic BpfWrite(rconn) 35155569Sbostic RMPCONN *rconn; 35255569Sbostic { 35355569Sbostic if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) { 35455569Sbostic syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn)); 35555569Sbostic return(0); 35655569Sbostic } 35755569Sbostic 35855569Sbostic return(1); 35955569Sbostic } 36055569Sbostic 36155569Sbostic /* 362*55600Sbostic ** BpfClose -- Close a BPF device. 36355569Sbostic ** 36455569Sbostic ** Parameters: 36555569Sbostic ** None. 36655569Sbostic ** 36755569Sbostic ** Returns: 36855569Sbostic ** Nothing. 36955569Sbostic ** 37055569Sbostic ** Side Effects: 37155569Sbostic ** None. 37255569Sbostic */ 373*55600Sbostic void 37455569Sbostic BpfClose() 37555569Sbostic { 37655569Sbostic struct ifreq ifr; 37755569Sbostic 37855569Sbostic if (BpfPkt != NULL) { 37955569Sbostic free((char *)BpfPkt); 38055569Sbostic BpfPkt = NULL; 38155569Sbostic } 38255569Sbostic 38355569Sbostic if (BpfFd == -1) 38455569Sbostic return; 38555569Sbostic 38655569Sbostic #ifdef MSG_EOR 38755569Sbostic ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; 38855569Sbostic #endif 38955569Sbostic ifr.ifr_addr.sa_family = AF_UNSPEC; 39055569Sbostic bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN); 39155569Sbostic if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0) 39255569Sbostic (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0); 39355569Sbostic 39455569Sbostic (void) close(BpfFd); 39555569Sbostic BpfFd = -1; 39655569Sbostic } 397