155569Sbostic /*
255569Sbostic * Copyright (c) 1988, 1992 The University of Utah and the Center
355569Sbostic * for Software Science (CSS).
4*61443Sbostic * Copyright (c) 1992, 1993
5*61443Sbostic * The Regents of the University of California. 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*61443Sbostic * @(#)bpf.c 8.1 (Berkeley) 06/04/93
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*61443Sbostic static char sccsid[] = "@(#)bpf.c 8.1 (Berkeley) 06/04/93";
2355569Sbostic #endif /* not lint */
2455569Sbostic
2555600Sbostic #include <sys/param.h>
2655569Sbostic #include <sys/ioctl.h>
2755600Sbostic #include <sys/socket.h>
2855569Sbostic
2955569Sbostic #include <net/if.h>
3055569Sbostic #include <net/bpf.h>
3155569Sbostic
3255600Sbostic #include <ctype.h>
3355600Sbostic #include <errno.h>
3455600Sbostic #include <fcntl.h>
3555600Sbostic #include <stdio.h>
3655600Sbostic #include <stdlib.h>
3755600Sbostic #include <string.h>
3855600Sbostic #include <syslog.h>
3955600Sbostic #include <unistd.h>
4055600Sbostic #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
BpfOpen()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 *
BpfGetIntfName(errmsg)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
BpfRead(rconn,doread)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 */
34955600Sbostic int
BpfWrite(rconn)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 /*
36255600Sbostic ** BpfClose -- Close a BPF device.
36355569Sbostic **
36455569Sbostic ** Parameters:
36555569Sbostic ** None.
36655569Sbostic **
36755569Sbostic ** Returns:
36855569Sbostic ** Nothing.
36955569Sbostic **
37055569Sbostic ** Side Effects:
37155569Sbostic ** None.
37255569Sbostic */
37355600Sbostic void
BpfClose()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