/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1988, 1992 The University of Utah and the Center4* for Software Science (CSS).5* Copyright (c) 1992, 19936* The Regents of the University of California. All rights reserved.7*8* This code is derived from software contributed to Berkeley by9* the Center for Software Science of the University of Utah Computer10* Science Department. CSS requests users of this software to return11* to [email protected] any improvements that they make and grant12* CSS redistribution rights.13*14* Redistribution and use in source and binary forms, with or without15* modification, are permitted provided that the following conditions16* are met:17* 1. Redistributions of source code must retain the above copyright18* notice, this list of conditions and the following disclaimer.19* 2. Redistributions in binary form must reproduce the above copyright20* notice, this list of conditions and the following disclaimer in the21* documentation and/or other materials provided with the distribution.22* 3. Neither the name of the University nor the names of its contributors23* may be used to endorse or promote products derived from this software24* without specific prior written permission.25*26* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND27* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE28* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE29* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE30* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL31* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS32* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)33* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT34* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY35* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF36* SUCH DAMAGE.37*38* From: Utah Hdr: bpf.c 3.1 92/07/0639* Author: Jeff Forys, University of Utah CSS40*/4142#include <sys/param.h>43#include <sys/ioctl.h>44#include <sys/socket.h>45#include <sys/time.h>4647#include <net/if.h>48#include <net/bpf.h>4950#include <ctype.h>51#include <errno.h>52#include <fcntl.h>53#include <stdio.h>54#include <stdlib.h>55#include <string.h>56#include <syslog.h>57#include <unistd.h>58#include "defs.h"59#include "pathnames.h"6061static int BpfFd = -1;62static unsigned BpfLen = 0;63static u_int8_t *BpfPkt = NULL;6465/*66** BpfOpen -- Open and initialize a BPF device.67**68** Parameters:69** None.70**71** Returns:72** File descriptor of opened BPF device (for select() etc).73**74** Side Effects:75** If an error is encountered, the program terminates here.76*/77int78BpfOpen(void)79{80struct ifreq ifr;81char bpfdev[32];82int n = 0;8384/*85* Open the first available BPF device.86*/87do {88(void) sprintf(bpfdev, _PATH_BPF, n++);89BpfFd = open(bpfdev, O_RDWR);90} while (BpfFd < 0 && (errno == EBUSY || errno == EPERM));9192if (BpfFd < 0) {93syslog(LOG_ERR, "bpf: no available devices: %m");94Exit(0);95}9697/*98* Set interface name for bpf device, get data link layer99* type and make sure it's type Ethernet.100*/101(void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name));102if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) {103syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName);104Exit(0);105}106107/*108* Make sure we are dealing with an Ethernet device.109*/110if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) {111syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m");112Exit(0);113}114if (n != DLT_EN10MB) {115syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported",116IntfName, n);117Exit(0);118}119120/*121* On read(), return packets immediately (do not buffer them).122*/123n = 1;124if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) {125syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m");126Exit(0);127}128129/*130* Try to enable the chip/driver's multicast address filter to131* grab our RMP address. If this fails, try promiscuous mode.132* If this fails, there's no way we are going to get any RMP133* packets so just exit here.134*/135#ifdef MSG_EOR136ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;137#endif138ifr.ifr_addr.sa_family = AF_UNSPEC;139memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0], RMP_ADDRLEN);140if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) {141syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m");142Exit(0);143}144145/*146* Ask BPF how much buffer space it requires and allocate one.147*/148if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) {149syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m");150Exit(0);151}152if (BpfPkt == NULL)153BpfPkt = (u_int8_t *)malloc(BpfLen);154155if (BpfPkt == NULL) {156syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)",157BpfLen);158Exit(0);159}160161/*162* Write a little program to snarf RMP Boot packets and stuff163* it down BPF's throat (i.e. set up the packet filter).164*/165{166#define RMP ((struct rmp_packet *)0)167static struct bpf_insn bpf_insn[] = {168{ BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap },169{ BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP },170{ BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl },171{ BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP },172{ BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap },173{ BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP },174{ BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET },175{ BPF_RET|BPF_K, 0, 0, 0x0 }176};177#undef RMP178static struct bpf_program bpf_pgm = {179sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn180};181182if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) {183syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m");184Exit(0);185}186}187188return(BpfFd);189}190191/*192** BPF GetIntfName -- Return the name of a network interface attached to193** the system, or 0 if none can be found. The interface194** must be configured up; the lowest unit number is195** preferred; loopback is ignored.196**197** Parameters:198** errmsg - if no network interface found, *errmsg explains why.199**200** Returns:201** A (static) pointer to interface name, or NULL on error.202**203** Side Effects:204** None.205*/206char *207BpfGetIntfName(char **errmsg)208{209struct ifreq ibuf[8], *ifrp, *ifend, *mp;210struct ifconf ifc;211int fd;212int minunit, n;213char *cp;214static char device[sizeof(ifrp->ifr_name)];215static char errbuf[128] = "No Error!";216217if (errmsg != NULL)218*errmsg = errbuf;219220if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {221(void) strcpy(errbuf, "bpf: socket: %m");222return(NULL);223}224ifc.ifc_len = sizeof ibuf;225ifc.ifc_buf = (caddr_t)ibuf;226227if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||228ifc.ifc_len < sizeof(struct ifreq)) {229(void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m");230return(NULL);231}232ifrp = ibuf;233ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);234235mp = NULL;236minunit = 666;237for (; ifrp < ifend; ++ifrp) {238if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) {239(void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m");240return(NULL);241}242243/*244* If interface is down or this is the loopback interface,245* ignore it.246*/247if ((ifrp->ifr_flags & IFF_UP) == 0 ||248#ifdef IFF_LOOPBACK249(ifrp->ifr_flags & IFF_LOOPBACK))250#else251(strcmp(ifrp->ifr_name, "lo0") == 0))252#endif253continue;254255for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)256;257n = atoi(cp);258if (n < minunit) {259minunit = n;260mp = ifrp;261}262}263264(void) close(fd);265if (mp == NULL) {266(void) strcpy(errbuf, "bpf: no interfaces found");267return(NULL);268}269270(void) strcpy(device, mp->ifr_name);271return(device);272}273274/*275** BpfRead -- Read packets from a BPF device and fill in `rconn'.276**277** Parameters:278** rconn - filled in with next packet.279** doread - is True if we can issue a read() syscall.280**281** Returns:282** True if `rconn' contains a new packet, False otherwise.283**284** Side Effects:285** None.286*/287int288BpfRead(RMPCONN *rconn, int doread)289{290int datlen, caplen, hdrlen;291static u_int8_t *bp = NULL, *ep = NULL;292int cc;293294/*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*/298if (doread) {299if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) {300syslog(LOG_ERR, "bpf: read: %m");301return(0);302} else {303bp = BpfPkt;304ep = BpfPkt + cc;305}306}307308#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*/313if (bp < ep) {314datlen = bhp->bh_datalen;315caplen = bhp->bh_caplen;316hdrlen = bhp->bh_hdrlen;317318if (caplen != datlen)319syslog(LOG_ERR,320"bpf: short packet dropped (%d of %d bytes)",321caplen, datlen);322else if (caplen > sizeof(struct rmp_packet))323syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)",324caplen);325else {326rconn->rmplen = caplen;327memmove((char *)&rconn->tstamp, (char *)&bhp->bh_tstamp,328sizeof(struct timeval));329memmove((char *)&rconn->rmp, (char *)bp + hdrlen, caplen);330}331bp += BPF_WORDALIGN(caplen + hdrlen);332return(1);333}334#undef bhp335336return(0);337}338339/*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*/351int352BpfWrite(RMPCONN *rconn)353{354if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) {355syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn));356return(0);357}358359return(1);360}361362/*363** BpfClose -- Close a BPF device.364**365** Parameters:366** None.367**368** Returns:369** Nothing.370**371** Side Effects:372** None.373*/374void375BpfClose(void)376{377struct ifreq ifr;378379if (BpfPkt != NULL) {380free((char *)BpfPkt);381BpfPkt = NULL;382}383384if (BpfFd == -1)385return;386387#ifdef MSG_EOR388ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;389#endif390ifr.ifr_addr.sa_family = AF_UNSPEC;391memmove((char *)&ifr.ifr_addr.sa_data[0], &RmpMcastAddr[0], RMP_ADDRLEN);392if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0)393(void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0);394395(void) close(BpfFd);396BpfFd = -1;397}398399400