summaryrefslogtreecommitdiffstats
path: root/libexec/rbootd
diff options
context:
space:
mode:
authorrgrimes <rgrimes@FreeBSD.org>1994-05-27 12:39:25 +0000
committerrgrimes <rgrimes@FreeBSD.org>1994-05-27 12:39:25 +0000
commit758c6e92c9f67b6722825ed7f11c4f775df5e2bc (patch)
tree98f432c884841050df97457a45ee310154679012 /libexec/rbootd
parente5bc52df062079b53ec568f2f4ae8f797c38933e (diff)
downloadFreeBSD-src-758c6e92c9f67b6722825ed7f11c4f775df5e2bc.zip
FreeBSD-src-758c6e92c9f67b6722825ed7f11c4f775df5e2bc.tar.gz
BSD 4.4 Lite Libexec Sources
Diffstat (limited to 'libexec/rbootd')
-rw-r--r--libexec/rbootd/Makefile11
-rw-r--r--libexec/rbootd/bpf.c422
-rw-r--r--libexec/rbootd/conf.c90
-rw-r--r--libexec/rbootd/defs.h185
-rw-r--r--libexec/rbootd/parseconf.c359
-rw-r--r--libexec/rbootd/pathnames.h51
-rw-r--r--libexec/rbootd/rbootd.8156
-rw-r--r--libexec/rbootd/rbootd.c508
-rw-r--r--libexec/rbootd/rmp.h95
-rw-r--r--libexec/rbootd/rmp_var.h244
-rw-r--r--libexec/rbootd/rmpproto.c593
-rw-r--r--libexec/rbootd/utils.c557
12 files changed, 3271 insertions, 0 deletions
diff --git a/libexec/rbootd/Makefile b/libexec/rbootd/Makefile
new file mode 100644
index 0000000..6e377fc
--- /dev/null
+++ b/libexec/rbootd/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/4/93
+
+PROG= rbootd
+SRCS= bpf.c conf.c parseconf.c rbootd.c rmpproto.c utils.c
+MAN8= rbootd.0
+
+afterinstall:
+ (cd ${.CURDIR}/bootdir && install -c -o ${BINOWN} -g ${BINGRP} \
+ -m 444 * ${DESTDIR}/usr/mdec/)
+
+.include <bsd.prog.mk>
diff --git a/libexec/rbootd/bpf.c b/libexec/rbootd/bpf.c
new file mode 100644
index 0000000..7ecd419
--- /dev/null
+++ b/libexec/rbootd/bpf.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bpf.c 8.1 (Berkeley) 6/4/93
+ *
+ * Utah $Hdr: bpf.c 3.1 92/07/06$
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)bpf.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/bpf.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "defs.h"
+#include "pathnames.h"
+
+static int BpfFd = -1;
+static unsigned BpfLen = 0;
+static u_char *BpfPkt = NULL;
+
+/*
+** BpfOpen -- Open and initialize a BPF device.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** File descriptor of opened BPF device (for select() etc).
+**
+** Side Effects:
+** If an error is encountered, the program terminates here.
+*/
+int
+BpfOpen()
+{
+ struct ifreq ifr;
+ char bpfdev[32];
+ int n = 0;
+
+ /*
+ * Open the first available BPF device.
+ */
+ do {
+ (void) sprintf(bpfdev, _PATH_BPF, n++);
+ BpfFd = open(bpfdev, O_RDWR);
+ } while (BpfFd < 0 && (errno == EBUSY || errno == EPERM));
+
+ if (BpfFd < 0) {
+ syslog(LOG_ERR, "bpf: no available devices: %m");
+ Exit(0);
+ }
+
+ /*
+ * Set interface name for bpf device, get data link layer
+ * type and make sure it's type Ethernet.
+ */
+ (void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name));
+ if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName);
+ Exit(0);
+ }
+
+ /*
+ * Make sure we are dealing with an Ethernet device.
+ */
+ if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m");
+ Exit(0);
+ }
+ if (n != DLT_EN10MB) {
+ syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported",
+ IntfName, n);
+ Exit(0);
+ }
+
+ /*
+ * On read(), return packets immediately (do not buffer them).
+ */
+ n = 1;
+ if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m");
+ Exit(0);
+ }
+
+ /*
+ * Try to enable the chip/driver's multicast address filter to
+ * grab our RMP address. If this fails, try promiscuous mode.
+ * If this fails, there's no way we are going to get any RMP
+ * packets so just exit here.
+ */
+#ifdef MSG_EOR
+ ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
+#endif
+ ifr.ifr_addr.sa_family = AF_UNSPEC;
+ bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN);
+ if (ioctl(BpfFd, SIOCADDMULTI, (caddr_t)&ifr) < 0) {
+ syslog(LOG_WARNING,
+ "bpf: can't add mcast addr (%m), setting promiscuous mode");
+
+ if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) {
+ syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m");
+ Exit(0);
+ }
+ }
+
+ /*
+ * Ask BPF how much buffer space it requires and allocate one.
+ */
+ if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m");
+ Exit(0);
+ }
+ if (BpfPkt == NULL)
+ BpfPkt = (u_char *)malloc(BpfLen);
+
+ if (BpfPkt == NULL) {
+ syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)",
+ BpfLen);
+ Exit(0);
+ }
+
+ /*
+ * Write a little program to snarf RMP Boot packets and stuff
+ * it down BPF's throat (i.e. set up the packet filter).
+ */
+ {
+#define RMP ((struct rmp_packet *)0)
+ static struct bpf_insn bpf_insn[] = {
+ { BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap },
+ { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP },
+ { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl },
+ { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP },
+ { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap },
+ { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP },
+ { BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET },
+ { BPF_RET|BPF_K, 0, 0, 0x0 }
+ };
+#undef RMP
+ static struct bpf_program bpf_pgm = {
+ sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn
+ };
+
+ if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) {
+ syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m");
+ Exit(0);
+ }
+ }
+
+ return(BpfFd);
+}
+
+/*
+** BPF GetIntfName -- Return the name of a network interface attached to
+** the system, or 0 if none can be found. The interface
+** must be configured up; the lowest unit number is
+** preferred; loopback is ignored.
+**
+** Parameters:
+** errmsg - if no network interface found, *errmsg explains why.
+**
+** Returns:
+** A (static) pointer to interface name, or NULL on error.
+**
+** Side Effects:
+** None.
+*/
+char *
+BpfGetIntfName(errmsg)
+ char **errmsg;
+{
+ struct ifreq ibuf[8], *ifrp, *ifend, *mp;
+ struct ifconf ifc;
+ int fd;
+ int minunit, n;
+ char *cp;
+ static char device[sizeof(ifrp->ifr_name)];
+ static char errbuf[128] = "No Error!";
+
+ if (errmsg != NULL)
+ *errmsg = errbuf;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ (void) strcpy(errbuf, "bpf: socket: %m");
+ return(NULL);
+ }
+ ifc.ifc_len = sizeof ibuf;
+ ifc.ifc_buf = (caddr_t)ibuf;
+
+#ifdef OSIOCGIFCONF
+ if (ioctl(fd, OSIOCGIFCONF, (char *)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ (void) strcpy(errbuf, "bpf: ioctl(OSIOCGIFCONF): %m");
+ return(NULL);
+ }
+#else
+ if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m");
+ return(NULL);
+ }
+#endif
+ ifrp = ibuf;
+ ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
+
+ mp = 0;
+ minunit = 666;
+ for (; ifrp < ifend; ++ifrp) {
+ if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) {
+ (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m");
+ return(NULL);
+ }
+
+ /*
+ * If interface is down or this is the loopback interface,
+ * ignore it.
+ */
+ if ((ifrp->ifr_flags & IFF_UP) == 0 ||
+#ifdef IFF_LOOPBACK
+ (ifrp->ifr_flags & IFF_LOOPBACK))
+#else
+ (strcmp(ifrp->ifr_name, "lo0") == 0))
+#endif
+ continue;
+
+ for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
+ ;
+ n = atoi(cp);
+ if (n < minunit) {
+ minunit = n;
+ mp = ifrp;
+ }
+ }
+
+ (void) close(fd);
+ if (mp == 0) {
+ (void) strcpy(errbuf, "bpf: no interfaces found");
+ return(NULL);
+ }
+
+ (void) strcpy(device, mp->ifr_name);
+ return(device);
+}
+
+/*
+** BpfRead -- Read packets from a BPF device and fill in `rconn'.
+**
+** Parameters:
+** rconn - filled in with next packet.
+** doread - is True if we can issue a read() syscall.
+**
+** Returns:
+** True if `rconn' contains a new packet, False otherwise.
+**
+** Side Effects:
+** None.
+*/
+int
+BpfRead(rconn, doread)
+ RMPCONN *rconn;
+ int doread;
+{
+ register int datlen, caplen, hdrlen;
+ static u_char *bp = NULL, *ep = NULL;
+ int cc;
+
+ /*
+ * The read() may block, or it may return one or more packets.
+ * We let the caller decide whether or not we can issue a read().
+ */
+ if (doread) {
+ if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) {
+ syslog(LOG_ERR, "bpf: read: %m");
+ return(0);
+ } else {
+ bp = BpfPkt;
+ ep = BpfPkt + cc;
+ }
+ }
+
+#define bhp ((struct bpf_hdr *)bp)
+ /*
+ * If there is a new packet in the buffer, stuff it into `rconn'
+ * and return a success indication.
+ */
+ if (bp < ep) {
+ datlen = bhp->bh_datalen;
+ caplen = bhp->bh_caplen;
+ hdrlen = bhp->bh_hdrlen;
+
+ if (caplen != datlen)
+ syslog(LOG_ERR,
+ "bpf: short packet dropped (%d of %d bytes)",
+ caplen, datlen);
+ else if (caplen > sizeof(struct rmp_packet))
+ syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)",
+ caplen);
+ else {
+ rconn->rmplen = caplen;
+ bcopy((char *)&bhp->bh_tstamp, (char *)&rconn->tstamp,
+ sizeof(struct timeval));
+ bcopy((char *)bp + hdrlen, (char *)&rconn->rmp, caplen);
+ }
+ bp += BPF_WORDALIGN(caplen + hdrlen);
+ return(1);
+ }
+#undef bhp
+
+ return(0);
+}
+
+/*
+** BpfWrite -- Write packet to BPF device.
+**
+** Parameters:
+** rconn - packet to send.
+**
+** Returns:
+** True if write succeeded, False otherwise.
+**
+** Side Effects:
+** None.
+*/
+int
+BpfWrite(rconn)
+ RMPCONN *rconn;
+{
+ if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) {
+ syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn));
+ return(0);
+ }
+
+ return(1);
+}
+
+/*
+** BpfClose -- Close a BPF device.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** None.
+*/
+void
+BpfClose()
+{
+ struct ifreq ifr;
+
+ if (BpfPkt != NULL) {
+ free((char *)BpfPkt);
+ BpfPkt = NULL;
+ }
+
+ if (BpfFd == -1)
+ return;
+
+#ifdef MSG_EOR
+ ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2;
+#endif
+ ifr.ifr_addr.sa_family = AF_UNSPEC;
+ bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN);
+ if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0)
+ (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0);
+
+ (void) close(BpfFd);
+ BpfFd = -1;
+}
diff --git a/libexec/rbootd/conf.c b/libexec/rbootd/conf.c
new file mode 100644
index 0000000..b890eea
--- /dev/null
+++ b/libexec/rbootd/conf.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)conf.c 8.1 (Berkeley) 6/4/93
+ *
+ * Utah $Hdr: conf.c 3.1 92/07/06$
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)conf.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#include "defs.h"
+#include "pathnames.h"
+
+/*
+** Define (and possibly initialize) global variables here.
+**
+** Caveat:
+** The maximum number of bootable files (`char *BootFiles[]') is
+** limited to C_MAXFILE (i.e. the maximum number of files that
+** can be spec'd in the configuration file). This was done to
+** simplify the boot file search code.
+*/
+
+char *ProgName; /* path-stripped argv[0] */
+char MyHost[MAXHOSTNAMELEN+1]; /* host name */
+int MyPid; /* process id */
+int DebugFlg = 0; /* set true if debugging */
+int BootAny = 0; /* set true if we boot anyone */
+
+char *ConfigFile = NULL; /* configuration file */
+char *DfltConfig = _PATH_RBOOTDCONF; /* default configuration file */
+char *PidFile = _PATH_RBOOTDPID; /* file w/pid of server */
+char *BootDir = _PATH_RBOOTDLIB; /* directory w/boot files */
+char *DbgFile = _PATH_RBOOTDDBG; /* debug output file */
+
+FILE *DbgFp = NULL; /* debug file pointer */
+char *IntfName = NULL; /* intf we are attached to */
+
+u_short SessionID = 0; /* generated session ID */
+
+char *BootFiles[C_MAXFILE]; /* list of boot files */
+
+CLIENT *Clients = NULL; /* list of addrs we'll accept */
+RMPCONN *RmpConns = NULL; /* list of active connections */
+
+char RmpMcastAddr[RMP_ADDRLEN] = RMP_ADDR; /* RMP multicast address */
diff --git a/libexec/rbootd/defs.h b/libexec/rbootd/defs.h
new file mode 100644
index 0000000..a2e0cd0
--- /dev/null
+++ b/libexec/rbootd/defs.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)defs.h 8.1 (Berkeley) 6/4/93
+ *
+ * Utah $Hdr: defs.h 3.1 92/07/06$
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#include "rmp.h"
+#include "rmp_var.h"
+
+/*
+** Common #define's and external variables. All other files should
+** include this.
+*/
+
+/*
+ * This may be defined in <sys/param.h>, if not, it's defined here.
+ */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+/*
+ * SIGUSR1 and SIGUSR2 are defined in <signal.h> for 4.3BSD systems.
+ */
+#ifndef SIGUSR1
+#define SIGUSR1 SIGEMT
+#endif
+#ifndef SIGUSR2
+#define SIGUSR2 SIGFPE
+#endif
+
+/*
+ * These can be faster & more efficient than strcmp()/strncmp()...
+ */
+#define STREQN(s1,s2) ((*s1 == *s2) && (strcmp(s1,s2) == 0))
+#define STRNEQN(s1,s2,n) ((*s1 == *s2) && (strncmp(s1,s2,n) == 0))
+
+/*
+ * Configuration file limitations.
+ */
+#define C_MAXFILE 10 /* max number of boot-able files */
+#define C_LINELEN 1024 /* max length of line */
+
+/*
+ * Direction of packet (used as argument to DispPkt).
+ */
+#define DIR_RCVD 0
+#define DIR_SENT 1
+#define DIR_NONE 2
+
+/*
+ * These need not be functions, so...
+ */
+#define FreeStr(str) free(str)
+#define FreeClient(cli) free(cli)
+#define GenSessID() (++SessionID ? SessionID: ++SessionID)
+
+/*
+ * Converting an Ethernet address to a string is done in many routines.
+ * Using `rmp.hp_hdr.saddr' works because this field is *never* changed;
+ * it will *always* contain the source address of the packet.
+ */
+#define EnetStr(rptr) GetEtherAddr(&(rptr)->rmp.hp_hdr.saddr[0])
+
+/*
+ * Every machine we can boot will have one of these allocated for it
+ * (unless there are no restrictions on who we can boot).
+ */
+typedef struct client_s {
+ u_char addr[RMP_ADDRLEN]; /* addr of machine */
+ char *files[C_MAXFILE]; /* boot-able files */
+ struct client_s *next; /* ptr to next */
+} CLIENT;
+
+/*
+ * Every active connection has one of these allocated for it.
+ */
+typedef struct rmpconn_s {
+ struct rmp_packet rmp; /* RMP packet */
+ int rmplen; /* length of packet */
+ struct timeval tstamp; /* last time active */
+ int bootfd; /* open boot file */
+ struct rmpconn_s *next; /* ptr to next */
+} RMPCONN;
+
+/*
+ * All these variables are defined in "conf.c".
+ */
+extern char *ProgName; /* path-stripped argv[0] */
+extern char MyHost[]; /* this hosts' name */
+extern int MyPid; /* this processes' ID */
+extern int DebugFlg; /* set true if debugging */
+extern int BootAny; /* set true if we can boot anyone */
+
+extern char *ConfigFile; /* configuration file */
+extern char *DfltConfig; /* default configuration file */
+extern char *DbgFile; /* debug output file */
+extern char *PidFile; /* file containing pid of server */
+extern char *BootDir; /* directory w/boot files */
+
+extern FILE *DbgFp; /* debug file pointer */
+extern char *IntfName; /* interface we are attached to */
+
+extern u_short SessionID; /* generated session ID */
+
+extern char *BootFiles[]; /* list of boot files */
+
+extern CLIENT *Clients; /* list of addrs we'll accept */
+extern RMPCONN *RmpConns; /* list of active connections */
+
+extern char RmpMcastAddr[]; /* RMP multicast address */
+
+void AddConn __P((RMPCONN *));
+int BootDone __P((RMPCONN *));
+void BpfClose __P((void));
+char *BpfGetIntfName __P((char **));
+int BpfOpen __P((void));
+int BpfRead __P((RMPCONN *, int));
+int BpfWrite __P((RMPCONN *));
+void DebugOff __P((int));
+void DebugOn __P((int));
+void DispPkt __P((RMPCONN *, int));
+void DoTimeout __P((void));
+void DspFlnm __P((u_int, char *));
+void Exit __P((int));
+CLIENT *FindClient __P((RMPCONN *));
+RMPCONN *FindConn __P((RMPCONN *));
+void FreeClients __P((void));
+void FreeConn __P((RMPCONN *));
+void FreeConns __P((void));
+int GetBootFiles __P((void));
+char *GetEtherAddr __P((u_char *));
+CLIENT *NewClient __P((u_char *));
+RMPCONN *NewConn __P((RMPCONN *));
+char *NewStr __P((char *));
+u_char *ParseAddr __P((char *));
+int ParseConfig __P((void));
+void ProcessPacket __P((RMPCONN *, CLIENT *));
+void ReConfig __P((int));
+void RemoveConn __P((RMPCONN *));
+int SendBootRepl __P((struct rmp_packet *, RMPCONN *, char *[]));
+int SendFileNo __P((struct rmp_packet *, RMPCONN *, char *[]));
+int SendPacket __P((RMPCONN *));
+int SendReadRepl __P((RMPCONN *));
+int SendServerID __P((RMPCONN *));
diff --git a/libexec/rbootd/parseconf.c b/libexec/rbootd/parseconf.c
new file mode 100644
index 0000000..d00436f
--- /dev/null
+++ b/libexec/rbootd/parseconf.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)parseconf.c 8.1 (Berkeley) 6/4/93
+ *
+ * Utah $Hdr: parseconf.c 3.1 92/07/06$
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)parseconf.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include "defs.h"
+
+/*
+** ParseConfig -- parse the config file into linked list of clients.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** 1 on success, 0 otherwise.
+**
+** Side Effects:
+** - Linked list of clients will be (re)allocated.
+**
+** Warnings:
+** - GetBootFiles() must be called before this routine
+** to create a linked list of default boot files.
+*/
+int
+ParseConfig()
+{
+ FILE *fp;
+ CLIENT *client;
+ u_char *addr;
+ char line[C_LINELEN];
+ register char *cp, *bcp;
+ register int i, j;
+ int omask, linecnt = 0;
+
+ if (BootAny) /* ignore config file */
+ return(1);
+
+ FreeClients(); /* delete old list of clients */
+
+ if ((fp = fopen(ConfigFile, "r")) == NULL) {
+ syslog(LOG_ERR, "ParseConfig: can't open config file (%s)",
+ ConfigFile);
+ return(0);
+ }
+
+ /*
+ * We've got to block SIGHUP to prevent reconfiguration while
+ * dealing with the linked list of Clients. This can be done
+ * when actually linking the new client into the list, but
+ * this could have unexpected results if the server was HUP'd
+ * whilst reconfiguring. Hence, it is done here.
+ */
+ omask = sigblock(sigmask(SIGHUP));
+
+ /*
+ * GETSTR positions `bcp' at the start of the current token,
+ * and null terminates it. `cp' is positioned at the start
+ * of the next token. spaces & commas are separators.
+ */
+#define GETSTR while (isspace(*cp) || *cp == ',') cp++; \
+ bcp = cp; \
+ while (*cp && *cp!=',' && !isspace(*cp)) cp++; \
+ if (*cp) *cp++ = '\0'
+
+ /*
+ * For each line, parse it into a new CLIENT struct.
+ */
+ while (fgets(line, C_LINELEN, fp) != NULL) {
+ linecnt++; /* line counter */
+
+ if (*line == '\0' || *line == '#') /* ignore comment */
+ continue;
+
+ if ((cp = index(line,'#')) != NULL) /* trash comments */
+ *cp = '\0';
+
+ cp = line; /* init `cp' */
+ GETSTR; /* get RMP addr */
+ if (bcp == cp) /* all delimiters */
+ continue;
+
+ /*
+ * Get an RMP address from a string. Abort on failure.
+ */
+ if ((addr = ParseAddr(bcp)) == NULL) {
+ syslog(LOG_ERR,
+ "ParseConfig: line %d: cant parse <%s>",
+ linecnt, bcp);
+ continue;
+ }
+
+ if ((client = NewClient(addr)) == NULL) /* alloc new client */
+ continue;
+
+ GETSTR; /* get first file */
+
+ /*
+ * If no boot files are spec'd, use the default list.
+ * Otherwise, validate each file (`bcp') against the
+ * list of boot-able files.
+ */
+ i = 0;
+ if (bcp == cp) /* no files spec'd */
+ for (; i < C_MAXFILE && BootFiles[i] != NULL; i++)
+ client->files[i] = BootFiles[i];
+ else {
+ do {
+ /*
+ * For each boot file spec'd, make sure it's
+ * in our list. If so, include a pointer to
+ * it in the CLIENT's list of boot files.
+ */
+ for (j = 0; ; j++) {
+ if (j==C_MAXFILE||BootFiles[j]==NULL) {
+ syslog(LOG_ERR, "ParseConfig: line %d: no boot file (%s)",
+ linecnt, bcp);
+ break;
+ }
+ if (STREQN(BootFiles[j], bcp)) {
+ if (i < C_MAXFILE)
+ client->files[i++] =
+ BootFiles[j];
+ else
+ syslog(LOG_ERR, "ParseConfig: line %d: too many boot files (%s)",
+ linecnt, bcp);
+ break;
+ }
+ }
+ GETSTR; /* get next file */
+ } while (bcp != cp);
+
+ /*
+ * Restricted list of boot files were spec'd,
+ * however, none of them were found. Since we
+ * apparently cant let them boot "just anything",
+ * the entire record is invalidated.
+ */
+ if (i == 0) {
+ FreeClient(client);
+ continue;
+ }
+ }
+
+ /*
+ * Link this client into the linked list of clients.
+ * SIGHUP has already been blocked.
+ */
+ if (Clients)
+ client->next = Clients;
+ Clients = client;
+ }
+
+ (void) fclose(fp); /* close config file */
+
+ (void) sigsetmask(omask); /* reset signal mask */
+
+ return(1); /* return success */
+}
+
+/*
+** ParseAddr -- Parse a string containing an RMP address.
+**
+** This routine is fairly liberal at parsing an RMP address. The
+** address must contain 6 octets consisting of between 0 and 2 hex
+** chars (upper/lower case) separated by colons. If two colons are
+** together (e.g. "::", the octet between them is recorded as being
+** zero. Hence, the following addrs are all valid and parse to the
+** same thing:
+**
+** 08:00:09:00:66:ad 8::9:0:66:AD 8::9::66:aD
+**
+** For clarity, an RMP address is really an Ethernet address, but
+** since the HP boot code uses IEEE 802.3, it's really an IEEE
+** 802.3 address. Of course, all of these are identical.
+**
+** Parameters:
+** str - string representation of an RMP address.
+**
+** Returns:
+** pointer to a static array of RMP_ADDRLEN bytes.
+**
+** Side Effects:
+** None.
+**
+** Warnings:
+** - The return value points to a static buffer; it must
+** be copied if it's to be saved.
+** - For speed, we assume a u_char consists of 8 bits.
+*/
+u_char *
+ParseAddr(str)
+ char *str;
+{
+ static u_char addr[RMP_ADDRLEN];
+ register char *cp;
+ register unsigned i;
+ register int part, subpart;
+
+ bzero((char *)&addr[0], RMP_ADDRLEN); /* zero static buffer */
+
+ part = subpart = 0;
+ for (cp = str; *cp; cp++) {
+ /*
+ * A colon (`:') must be used to delimit each octet.
+ */
+ if (*cp == ':') {
+ if (++part == RMP_ADDRLEN) /* too many parts */
+ return(NULL);
+ subpart = 0;
+ continue;
+ }
+
+ /*
+ * Convert hex character to an integer.
+ */
+ if (isdigit(*cp))
+ i = *cp - '0';
+ else {
+ i = (isupper(*cp)? tolower(*cp): *cp) - 'a' + 10;
+ if (i < 10 || i > 15) /* not a hex char */
+ return(NULL);
+ }
+
+ if (subpart++) {
+ if (subpart > 2) /* too many hex chars */
+ return(NULL);
+ addr[part] <<= 4;
+ }
+ addr[part] |= i;
+ }
+
+ if (part != (RMP_ADDRLEN-1)) /* too few parts */
+ return(NULL);
+
+ return(&addr[0]);
+}
+
+/*
+** GetBootFiles -- record list of files in current (boot) directory.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Number of boot files on success, 0 on failure.
+**
+** Side Effects:
+** Strings in `BootFiles' are freed/allocated.
+**
+** Warnings:
+** - After this routine is called, ParseConfig() must be
+** called to re-order it's list of boot file pointers.
+*/
+int
+GetBootFiles()
+{
+ DIR *dfd;
+ struct stat statb;
+ register struct dirent *dp;
+ register int i;
+
+ /*
+ * Free the current list of boot files.
+ */
+ for (i = 0; i < C_MAXFILE && BootFiles[i] != NULL; i++) {
+ FreeStr(BootFiles[i]);
+ BootFiles[i] = NULL;
+ }
+
+ /*
+ * Open current directory to read boot file names.
+ */
+ if ((dfd = opendir(".")) == NULL) { /* open BootDir */
+ syslog(LOG_ERR, "GetBootFiles: can't open directory (%s)\n",
+ BootDir);
+ return(0);
+ }
+
+ /*
+ * Read each boot file name and allocate space for it in the
+ * list of boot files (BootFiles). All boot files read after
+ * C_MAXFILE will be ignored.
+ */
+ i = 0;
+ for (dp = readdir(dfd); dp != NULL; dp = readdir(dfd)) {
+ if (stat(dp->d_name, &statb) < 0 ||
+ (statb.st_mode & S_IFMT) != S_IFREG)
+ continue;
+ if (i == C_MAXFILE)
+ syslog(LOG_ERR,
+ "GetBootFiles: too many boot files (%s ignored)",
+ dp->d_name);
+ else if ((BootFiles[i] = NewStr(dp->d_name)) != NULL)
+ i++;
+ }
+
+ (void) closedir(dfd); /* close BootDir */
+
+ if (i == 0) /* cant find any boot files */
+ syslog(LOG_ERR, "GetBootFiles: no boot files (%s)\n", BootDir);
+
+ return(i);
+}
diff --git a/libexec/rbootd/pathnames.h b/libexec/rbootd/pathnames.h
new file mode 100644
index 0000000..d960dce
--- /dev/null
+++ b/libexec/rbootd/pathnames.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ *
+ * Utah $Hdr: pathnames.h 3.1 92/07/06$
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#define _PATH_BPF "/dev/bpf%d"
+#define _PATH_RBOOTDCONF "/etc/rbootd.conf"
+#define _PATH_RBOOTDDBG "/tmp/rbootd.dbg"
+#define _PATH_RBOOTDLIB "/usr/mdec/rbootd"
+#define _PATH_RBOOTDPID "/var/run/rbootd.pid"
diff --git a/libexec/rbootd/rbootd.8 b/libexec/rbootd/rbootd.8
new file mode 100644
index 0000000..f4eb364
--- /dev/null
+++ b/libexec/rbootd/rbootd.8
@@ -0,0 +1,156 @@
+.\" Copyright (c) 1988, 1992 The University of Utah and the Center
+.\" for Software Science (CSS).
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Center for Software Science of the University of Utah Computer
+.\" Science Department. CSS requests users of this software to return
+.\" to css-dist@cs.utah.edu any improvements that they make and grant
+.\" CSS redistribution rights.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)rbootd.8 8.2 (Berkeley) 12/11/93
+.\"
+.\" Utah $Hdr: rbootd.man 3.1 92/07/06$
+.\" Author: Jeff Forys, University of Utah CSS
+.\"
+.Dd "December 11, 1993"
+.Dt RBOOTD 8
+.Os
+.Sh NAME
+.Nm rbootd
+.Nd HP remote boot server
+.Sh SYNOPSIS
+.Nm rbootd
+.Op Fl ad
+.Op Fl i Ar interface
+.Op config_file
+.Sh DESCRIPTION
+The
+.Nm rbootd
+utility services boot requests from Hewlett-Packard workstations over a
+local area network.
+All boot files must reside in the boot file directory; further, if a
+client supplies path information in its boot request, it will be silently
+stripped away before processing.
+By default,
+.Nm rbootd
+only responds to requests from machines listed in its configuration file.
+.Pp
+The options are as follows:
+.Bl -tag -width Fl
+.It Fl a
+Respond to boot requests from any machine.
+The configuration file is ignored if this option is specified.
+.It Fl d
+Run
+.Nm rbootd
+in debug mode.
+Packets sent and received are displayed to the terminal.
+.It Fl i Ar interface
+Service boot requests on specified interface.
+If unspecified,
+.Nm rbootd
+searches the system interface list for the lowest numbered, configured
+``up'' interface (excluding loopback).
+Ties are broken by choosing the earliest match.
+.El
+.Pp
+Specifying
+.Ar config_file
+on the command line causes
+.Nm rbootd
+to use a different configuration file from the default.
+.Pp
+The configuration file is a text file where each line describes a particular
+machine.
+A line must start with a machine's Ethernet address followed by an optional
+list of boot file names.
+An Ethernet address is specified in hexadecimal with each of its six octets
+separated by a colon.
+The boot file names come from the boot file directory.
+The ethernet address and boot file(s) must be separated by white-space
+and/or comma characters.
+A pound sign causes the remainder of a line to be ignored.
+.Pp
+Here is a sample configuration file:
+.Bl -column 08:00:09:0:66:ad SYSHPBSD,SYSHPUX "# vandy (anything)"
+.It #
+.It # ethernet addr boot file(s) comments
+.It #
+.It 08:00:09:0:66:ad SYSHPBSD # snake (4.3BSD)
+.It 08:00:09:0:59:5b # vandy (anything)
+.It 8::9:1:C6:75 SYSHPBSD,SYSHPUX # jaguar (either)
+.El
+.Pp
+.Nm Rbootd
+logs status and error messages via
+.Xr syslog 3 .
+A startup message is always logged, and in the case of fatal errors (or
+deadly signals) a message is logged announcing the server's termination.
+In general, a non-fatal error is handled by ignoring the event that caused
+it (e.g. an invalid Ethernet address in the config file causes that line
+to be invalidated).
+.Pp
+The following signals have the specified effect when sent to the server
+process using the
+.Xr kill 1
+command:
+.Bl -tag -width SIGUSR1 -offset -compact
+.It SIGHUP
+Drop all active connections and reconfigure.
+.It SIGUSR1
+Turn on debugging, do nothing if already on.
+.It SIGUSR2
+Turn off debugging, do nothing if already off.
+.El
+.Sh "FILES"
+.Bl -tag -width /usr/libexec/rbootd -compact
+.It /dev/bpf#
+packet-filter device
+.It /etc/rbootd.conf
+configuration file
+.It /tmp/rbootd.dbg
+debug output
+.It /usr/mdec/rbootd
+directory containing boot files
+.It /var/run/rbootd.pid
+process id
+.El
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr socket 2 ,
+.Xr signal 3 ,
+.Xr syslog 3 ,
+.Xr rmp 4
+.Sh BUGS
+If multiple servers are started on the same interface, each will receive
+and respond to the same boot packets.
diff --git a/libexec/rbootd/rbootd.c b/libexec/rbootd/rbootd.c
new file mode 100644
index 0000000..aa01583
--- /dev/null
+++ b/libexec/rbootd/rbootd.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)rbootd.c 8.2 (Berkeley) 2/22/94
+ *
+ * Utah $Hdr: rbootd.c 3.1 92/07/06$
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)rbootd.c 8.2 (Berkeley) 2/22/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "defs.h"
+
+
+/* fd mask macros (backward compatibility with 4.2BSD) */
+#ifndef FD_SET
+#ifdef notdef
+typedef struct fd_set { /* this should already be in 4.2 */
+ int fds_bits[1];
+} fd_set;
+#endif
+#define FD_ZERO(p) ((p)->fds_bits[0] = 0)
+#define FD_SET(n, p) ((p)->fds_bits[0] |= (1 << (n)))
+#define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1 << (n)))
+#define FD_ISSET(n, p) ((p)->fds_bits[0] & (1 << (n)))
+#endif
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c, fd, omask, maxfds;
+ fd_set rset;
+
+ /*
+ * Find what name we are running under.
+ */
+ ProgName = (ProgName = rindex(argv[0],'/')) ? ++ProgName : *argv;
+
+ /*
+ * Close any open file descriptors.
+ * Temporarily leave stdin & stdout open for `-d',
+ * and stderr open for any pre-syslog error messages.
+ */
+ {
+ int i, nfds = getdtablesize();
+
+ for (i = 0; i < nfds; i++)
+ if (i != fileno(stdin) && i != fileno(stdout) &&
+ i != fileno(stderr))
+ (void) close(i);
+ }
+
+ /*
+ * Parse any arguments.
+ */
+ while ((c = getopt(argc, argv, "adi:")) != EOF)
+ switch(c) {
+ case 'a':
+ BootAny++;
+ break;
+ case 'd':
+ DebugFlg++;
+ break;
+ case 'i':
+ IntfName = optarg;
+ break;
+ }
+ for (; optind < argc; optind++) {
+ if (ConfigFile == NULL)
+ ConfigFile = argv[optind];
+ else {
+ fprintf(stderr,
+ "%s: too many config files (`%s' ignored)\n",
+ ProgName, argv[optind]);
+ }
+ }
+
+ if (ConfigFile == NULL) /* use default config file */
+ ConfigFile = DfltConfig;
+
+ if (DebugFlg) {
+ DbgFp = stdout; /* output to stdout */
+
+ (void) signal(SIGUSR1, SIG_IGN); /* dont muck w/DbgFp */
+ (void) signal(SIGUSR2, SIG_IGN);
+ } else {
+ (void) fclose(stdin); /* dont need these */
+ (void) fclose(stdout);
+
+ /*
+ * Fork off a child to do the work & exit.
+ */
+ switch(fork()) {
+ case -1: /* fork failed */
+ fprintf(stderr, "%s: ", ProgName);
+ perror("fork");
+ Exit(0);
+ case 0: /* this is the CHILD */
+ break;
+ default: /* this is the PARENT */
+ _exit(0);
+ }
+
+ /*
+ * Try to disassociate from the current tty.
+ */
+ {
+ char *devtty = "/dev/tty";
+ int i;
+
+ if ((i = open(devtty, O_RDWR)) < 0) {
+ /* probably already disassociated */
+ if (setpgrp(0, 0) < 0) {
+ fprintf(stderr, "%s: ", ProgName);
+ perror("setpgrp");
+ }
+ } else {
+ if (ioctl(i, (u_long)TIOCNOTTY, (char *)0) < 0){
+ fprintf(stderr, "%s: ", ProgName);
+ perror("ioctl");
+ }
+ (void) close(i);
+ }
+ }
+
+ (void) signal(SIGUSR1, DebugOn);
+ (void) signal(SIGUSR2, DebugOff);
+ }
+
+ (void) fclose(stderr); /* finished with it */
+
+#ifdef SYSLOG4_2
+ openlog(ProgName, LOG_PID);
+#else
+ openlog(ProgName, LOG_PID, LOG_DAEMON);
+#endif
+
+ /*
+ * If no interface was specified, get one now.
+ *
+ * This is convoluted because we want to get the default interface
+ * name for the syslog("restarted") message. If BpfGetIntfName()
+ * runs into an error, it will return a syslog-able error message
+ * (in `errmsg') which will be displayed here.
+ */
+ if (IntfName == NULL) {
+ char *errmsg;
+
+ if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) {
+ syslog(LOG_NOTICE, "restarted (??)");
+ syslog(LOG_ERR, errmsg);
+ Exit(0);
+ }
+ }
+
+ syslog(LOG_NOTICE, "restarted (%s)", IntfName);
+
+ (void) signal(SIGHUP, ReConfig);
+ (void) signal(SIGINT, Exit);
+ (void) signal(SIGTERM, Exit);
+
+ /*
+ * Grab our host name and pid.
+ */
+ if (gethostname(MyHost, MAXHOSTNAMELEN) < 0) {
+ syslog(LOG_ERR, "gethostname: %m");
+ Exit(0);
+ }
+ MyHost[MAXHOSTNAMELEN] = '\0';
+
+ MyPid = getpid();
+
+ /*
+ * Write proc's pid to a file.
+ */
+ {
+ FILE *fp;
+
+ if ((fp = fopen(PidFile, "w")) != NULL) {
+ (void) fprintf(fp, "%d\n", MyPid);
+ (void) fclose(fp);
+ } else {
+ syslog(LOG_WARNING, "fopen: failed (%s)", PidFile);
+ }
+ }
+
+ /*
+ * All boot files are relative to the boot directory, we might
+ * as well chdir() there to make life easier.
+ */
+ if (chdir(BootDir) < 0) {
+ syslog(LOG_ERR, "chdir: %m (%s)", BootDir);
+ Exit(0);
+ }
+
+ /*
+ * Initial configuration.
+ */
+ omask = sigblock(sigmask(SIGHUP)); /* prevent reconfig's */
+ if (GetBootFiles() == 0) /* get list of boot files */
+ Exit(0);
+ if (ParseConfig() == 0) /* parse config file */
+ Exit(0);
+
+ /*
+ * Open and initialize a BPF device for the appropriate interface.
+ * If an error is encountered, a message is displayed and Exit()
+ * is called.
+ */
+ fd = BpfOpen();
+
+ (void) sigsetmask(omask); /* allow reconfig's */
+
+ /*
+ * Main loop: receive a packet, determine where it came from,
+ * and if we service this host, call routine to handle request.
+ */
+ maxfds = fd + 1;
+ FD_ZERO(&rset);
+ FD_SET(fd, &rset);
+ for (;;) {
+ struct timeval timeout;
+ fd_set r;
+ int nsel;
+
+ r = rset;
+
+ if (RmpConns == NULL) { /* timeout isnt necessary */
+ nsel = select(maxfds, &r, (fd_set *)0, (fd_set *)0,
+ (struct timeval *)0);
+ } else {
+ timeout.tv_sec = RMP_TIMEOUT;
+ timeout.tv_usec = 0;
+ nsel = select(maxfds, &r, (fd_set *)0, (fd_set *)0,
+ &timeout);
+ }
+
+ if (nsel < 0) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "select: %m");
+ Exit(0);
+ } else if (nsel == 0) { /* timeout */
+ DoTimeout(); /* clear stale conns */
+ continue;
+ }
+
+ if (FD_ISSET(fd, &r)) {
+ RMPCONN rconn;
+ CLIENT *client, *FindClient();
+ int doread = 1;
+
+ while (BpfRead(&rconn, doread)) {
+ doread = 0;
+
+ if (DbgFp != NULL) /* display packet */
+ DispPkt(&rconn,DIR_RCVD);
+
+ omask = sigblock(sigmask(SIGHUP));
+
+ /*
+ * If we do not restrict service, set the
+ * client to NULL (ProcessPacket() handles
+ * this). Otherwise, check that we can
+ * service this host; if not, log a message
+ * and ignore the packet.
+ */
+ if (BootAny) {
+ client = NULL;
+ } else if ((client=FindClient(&rconn))==NULL) {
+ syslog(LOG_INFO,
+ "%s: boot packet ignored",
+ EnetStr(&rconn));
+ (void) sigsetmask(omask);
+ continue;
+ }
+
+ ProcessPacket(&rconn,client);
+
+ (void) sigsetmask(omask);
+ }
+ }
+ }
+}
+
+/*
+** DoTimeout -- Free any connections that have timed out.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Timed out connections in `RmpConns' will be freed.
+*/
+void
+DoTimeout()
+{
+ register RMPCONN *rtmp;
+ struct timeval now;
+
+ (void) gettimeofday(&now, (struct timezone *)0);
+
+ /*
+ * For each active connection, if RMP_TIMEOUT seconds have passed
+ * since the last packet was sent, delete the connection.
+ */
+ for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
+ if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) {
+ syslog(LOG_WARNING, "%s: connection timed out (%u)",
+ EnetStr(rtmp), rtmp->rmp.r_type);
+ RemoveConn(rtmp);
+ }
+}
+
+/*
+** FindClient -- Find client associated with a packet.
+**
+** Parameters:
+** rconn - the new packet.
+**
+** Returns:
+** Pointer to client info if found, NULL otherwise.
+**
+** Side Effects:
+** None.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked since
+** a reconfigure can invalidate the information returned.
+*/
+
+CLIENT *
+FindClient(rconn)
+ register RMPCONN *rconn;
+{
+ register CLIENT *ctmp;
+
+ for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next)
+ if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
+ (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0)
+ break;
+
+ return(ctmp);
+}
+
+/*
+** Exit -- Log an error message and exit.
+**
+** Parameters:
+** sig - caught signal (or zero if not dying on a signal).
+**
+** Returns:
+** Does not return.
+**
+** Side Effects:
+** - This process ceases to exist.
+*/
+void
+Exit(sig)
+ int sig;
+{
+ if (sig > 0)
+ syslog(LOG_ERR, "going down on signal %d", sig);
+ else
+ syslog(LOG_ERR, "going down with fatal error");
+ BpfClose();
+ exit(1);
+}
+
+/*
+** ReConfig -- Get new list of boot files and reread config files.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - All active connections are dropped.
+** - List of boot-able files is changed.
+** - List of clients is changed.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+ReConfig(signo)
+ int signo;
+{
+ syslog(LOG_NOTICE, "reconfiguring boot server");
+
+ FreeConns();
+
+ if (GetBootFiles() == 0)
+ Exit(0);
+
+ if (ParseConfig() == 0)
+ Exit(0);
+}
+
+/*
+** DebugOff -- Turn off debugging.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Debug file is closed.
+*/
+void
+DebugOff(signo)
+ int signo;
+{
+ if (DbgFp != NULL)
+ (void) fclose(DbgFp);
+
+ DbgFp = NULL;
+}
+
+/*
+** DebugOn -- Turn on debugging.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Debug file is opened/truncated if not already opened,
+** otherwise do nothing.
+*/
+void
+DebugOn(signo)
+ int signo;
+{
+ if (DbgFp == NULL) {
+ if ((DbgFp = fopen(DbgFile, "w")) == NULL)
+ syslog(LOG_ERR, "can't open debug file (%s)", DbgFile);
+ }
+}
diff --git a/libexec/rbootd/rmp.h b/libexec/rbootd/rmp.h
new file mode 100644
index 0000000..d3b0167
--- /dev/null
+++ b/libexec/rbootd/rmp.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)rmp.h 8.1 (Berkeley) 6/4/93
+ *
+ * Utah $Hdr: rmp.h 3.1 92/07/06$
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+/*
+ * Define MIN/MAX sizes of RMP (ethernet) packet.
+ * For ease of computation, the 4 octet CRC field is not included.
+ *
+ * MCLBYTES is for bpfwrite(); it is adamant about using a cluster.
+ */
+
+#define RMP_MAX_PACKET MIN(1514,MCLBYTES)
+#define RMP_MIN_PACKET 60
+
+/*
+ * Define RMP/Ethernet Multicast address (9:0:9:0:0:4) and its length.
+ */
+#define RMP_ADDR { 0x9, 0x0, 0x9, 0x0, 0x0, 0x4 }
+#define RMP_ADDRLEN 6
+
+/*
+ * Define IEEE802.2 (Logical Link Control) information.
+ */
+#define IEEE_DSAP_HP 0xF8 /* Destination Service Access Point */
+#define IEEE_SSAP_HP 0xF8 /* Source Service Access Point */
+#define IEEE_CNTL_HP 0x0300 /* Type 1 / I format control information */
+
+#define HPEXT_DXSAP 0x608 /* HP Destination Service Access Point */
+#define HPEXT_SXSAP 0x609 /* HP Source Service Access Point */
+
+/*
+ * 802.3-style "Ethernet" header.
+ */
+
+struct hp_hdr {
+ u_char daddr[RMP_ADDRLEN];
+ u_char saddr[RMP_ADDRLEN];
+ u_short len;
+};
+
+/*
+ * HP uses 802.2 LLC with their own local extensions. This struct makes
+ * sence out of this data (encapsulated in the above 802.3 packet).
+ */
+
+struct hp_llc {
+ u_char dsap; /* 802.2 DSAP */
+ u_char ssap; /* 802.2 SSAP */
+ u_short cntrl; /* 802.2 control field */
+ u_short filler; /* HP filler (must be zero) */
+ u_short dxsap; /* HP extended DSAP */
+ u_short sxsap; /* HP extended SSAP */
+};
diff --git a/libexec/rbootd/rmp_var.h b/libexec/rbootd/rmp_var.h
new file mode 100644
index 0000000..7df1e87
--- /dev/null
+++ b/libexec/rbootd/rmp_var.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)rmp_var.h 8.1 (Berkeley) 6/4/93
+ *
+ * Utah $Hdr: rmp_var.h 3.1 92/07/06$
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+/*
+ * Possible values for "rmp_type" fields.
+ */
+
+#define RMP_BOOT_REQ 1 /* boot request packet */
+#define RMP_BOOT_REPL 129 /* boot reply packet */
+#define RMP_READ_REQ 2 /* read request packet */
+#define RMP_READ_REPL 130 /* read reply packet */
+#define RMP_BOOT_DONE 3 /* boot complete packet */
+
+/*
+ * Useful constants.
+ */
+
+#define RMP_VERSION 2 /* protocol version */
+#define RMP_TIMEOUT 600 /* timeout connection after ten minutes */
+#define RMP_PROBESID 0xffff /* session ID for probes */
+#define RMP_HOSTLEN 13 /* max length of server's name */
+#define RMP_MACHLEN 20 /* length of machine type field */
+
+/*
+ * RMP error codes
+ */
+
+#define RMP_E_OKAY 0
+#define RMP_E_EOF 2 /* read reply: returned end of file */
+#define RMP_E_ABORT 3 /* abort operation */
+#define RMP_E_BUSY 4 /* boot reply: server busy */
+#define RMP_E_TIMEOUT 5 /* lengthen time out (not implemented) */
+#define RMP_E_NOFILE 16 /* boot reply: file does not exist */
+#define RMP_E_OPENFILE 17 /* boot reply: file open failed */
+#define RMP_E_NODFLT 18 /* boot reply: default file does not exist */
+#define RMP_E_OPENDFLT 19 /* boot reply: default file open failed */
+#define RMP_E_BADSID 25 /* read reply: bad session ID */
+#define RMP_E_BADPACKET 27 /* Bad packet detected */
+
+/*
+ * RMPDATALEN is the maximum number of data octets that can be stuffed
+ * into an RMP packet. This excludes the 802.2 LLC w/HP extensions.
+ */
+#define RMPDATALEN (RMP_MAX_PACKET - (sizeof(struct hp_hdr) + \
+ sizeof(struct hp_llc)))
+
+/*
+ * Define sizes of packets we send. Boot and Read replies are variable
+ * in length depending on the length of `s'.
+ *
+ * Also, define how much space `restofpkt' can take up for outgoing
+ * Boot and Read replies. Boot Request packets are effectively
+ * limited to 255 bytes due to the preceding 1-byte length field.
+ */
+
+#define RMPBOOTSIZE(s) (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \
+ sizeof(struct rmp_boot_repl) + s - sizeof(restofpkt))
+#define RMPREADSIZE(s) (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \
+ sizeof(struct rmp_read_repl) + s - sizeof(restofpkt) \
+ - sizeof(u_char))
+#define RMPDONESIZE (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \
+ sizeof(struct rmp_boot_done))
+#define RMPBOOTDATA 255
+#define RMPREADDATA (RMPDATALEN - \
+ (2*sizeof(u_char)+sizeof(u_short)+sizeof(u_word)))
+
+/*
+ * This protocol defines some field sizes as "rest of ethernet packet".
+ * There is no easy way to specify this in C, so we use a one character
+ * field to denote it, and index past it to the end of the packet.
+ */
+
+typedef char restofpkt;
+
+/*
+ * Due to the RMP packet layout, we'll run into alignment problems
+ * on machines that cant access words on half-word boundaries. If
+ * you know that your machine does not suffer from this problem,
+ * add it to the hp300 #define below.
+ *
+ * The following macros are used to deal with this problem:
+ * WORDZE(w) Return True if u_word `w' is zero, False otherwise.
+ * ZEROWORD(w) Set u_word `w' to zero.
+ * COPYWORD(w1,w2) Copy u_word `w1' to `w2'.
+ * GETWORD(w,i) Copy u_word `w' into int `i'.
+ * PUTWORD(i,w) Copy int `i' into u_word `w'.
+ *
+ * N.B. We do not support little endian alignment-challenged machines.
+ */
+#if defined(vax) || defined(tahoe) || defined(hp300)
+
+typedef u_int u_word;
+
+#define WORDZE(w) ((w) == 0)
+#define ZEROWORD(w) (w) = 0
+#define COPYWORD(w1,w2) (w2) = (w1)
+#define GETWORD(w, i) (i) = (w)
+#define PUTWORD(i, w) (w) = (i)
+
+#else
+
+#define _WORD_HIGHPART 0 /* XXX: assume Big Endian for now */
+#define _WORD_LOWPART 1
+
+typedef struct _uword { u_short val[2]; } u_word;
+
+#define WORDZE(w) \
+ ((w.val[_WORD_HIGHPART] == 0) && (w.val[_WORD_LOWPART] == 0))
+#define ZEROWORD(w) \
+ (w).val[_WORD_HIGHPART] = (w).val[_WORD_LOWPART] = 0
+#define COPYWORD(w1, w2) \
+ { (w2).val[_WORD_HIGHPART] = (w1).val[_WORD_HIGHPART]; \
+ (w2).val[_WORD_LOWPART] = (w1).val[_WORD_LOWPART]; \
+ }
+#define GETWORD(w, i) \
+ (i) = (((u_int)(w).val[_WORD_HIGHPART]) << 16) | (w).val[_WORD_LOWPART]
+#define PUTWORD(i, w) \
+ { (w).val[_WORD_HIGHPART] = (u_short) (((i) >> 16) & 0xffff); \
+ (w).val[_WORD_LOWPART] = (u_short) (i & 0xffff); \
+ }
+
+#endif
+
+/*
+ * Packet structures.
+ */
+
+struct rmp_raw { /* generic RMP packet */
+ u_char rmp_type; /* packet type */
+ u_char rmp_rawdata[RMPDATALEN-1];
+};
+
+struct rmp_boot_req { /* boot request */
+ u_char rmp_type; /* packet type (RMP_BOOT_REQ) */
+ u_char rmp_retcode; /* return code (0) */
+ u_word rmp_seqno; /* sequence number (real time clock) */
+ u_short rmp_session; /* session id (normally 0) */
+ u_short rmp_version; /* protocol version (RMP_VERSION) */
+ char rmp_machtype[RMP_MACHLEN]; /* machine type */
+ u_char rmp_flnmsize; /* length of rmp_flnm */
+ restofpkt rmp_flnm; /* name of file to be read */
+};
+
+struct rmp_boot_repl { /* boot reply */
+ u_char rmp_type; /* packet type (RMP_BOOT_REPL) */
+ u_char rmp_retcode; /* return code (normally 0) */
+ u_word rmp_seqno; /* sequence number (from boot req) */
+ u_short rmp_session; /* session id (generated) */
+ u_short rmp_version; /* protocol version (RMP_VERSION) */
+ u_char rmp_flnmsize; /* length of rmp_flnm */
+ restofpkt rmp_flnm; /* name of file (from boot req) */
+};
+
+struct rmp_read_req { /* read request */
+ u_char rmp_type; /* packet type (RMP_READ_REQ) */
+ u_char rmp_retcode; /* return code (0) */
+ u_word rmp_offset; /* file relative byte offset */
+ u_short rmp_session; /* session id (from boot repl) */
+ u_short rmp_size; /* max no of bytes to send */
+};
+
+struct rmp_read_repl { /* read reply */
+ u_char rmp_type; /* packet type (RMP_READ_REPL) */
+ u_char rmp_retcode; /* return code (normally 0) */
+ u_word rmp_offset; /* byte offset (from read req) */
+ u_short rmp_session; /* session id (from read req) */
+ restofpkt rmp_data; /* data (max size from read req) */
+ u_char rmp_unused; /* padding to 16-bit boundary */
+};
+
+struct rmp_boot_done { /* boot complete */
+ u_char rmp_type; /* packet type (RMP_BOOT_DONE) */
+ u_char rmp_retcode; /* return code (0) */
+ u_word rmp_unused; /* not used (0) */
+ u_short rmp_session; /* session id (from read repl) */
+};
+
+struct rmp_packet {
+ struct hp_hdr hp_hdr;
+ struct hp_llc hp_llc;
+ union {
+ struct rmp_boot_req rmp_brq; /* boot request */
+ struct rmp_boot_repl rmp_brpl; /* boot reply */
+ struct rmp_read_req rmp_rrq; /* read request */
+ struct rmp_read_repl rmp_rrpl; /* read reply */
+ struct rmp_boot_done rmp_done; /* boot complete */
+ struct rmp_raw rmp_raw; /* raw data */
+ } rmp_proto;
+};
+
+/*
+ * Make life easier...
+ */
+
+#define r_type rmp_proto.rmp_raw.rmp_type
+#define r_data rmp_proto.rmp_raw.rmp_data
+#define r_brq rmp_proto.rmp_brq
+#define r_brpl rmp_proto.rmp_brpl
+#define r_rrq rmp_proto.rmp_rrq
+#define r_rrpl rmp_proto.rmp_rrpl
+#define r_done rmp_proto.rmp_done
diff --git a/libexec/rbootd/rmpproto.c b/libexec/rbootd/rmpproto.c
new file mode 100644
index 0000000..d0a8d4a
--- /dev/null
+++ b/libexec/rbootd/rmpproto.c
@@ -0,0 +1,593 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)rmpproto.c 8.1 (Berkeley) 6/4/93
+ *
+ * Utah $Hdr: rmpproto.c 3.1 92/07/06$
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)rmpproto.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include "defs.h"
+
+/*
+** ProcessPacket -- determine packet type and do what's required.
+**
+** An RMP BOOT packet has been received. Look at the type field
+** and process Boot Requests, Read Requests, and Boot Complete
+** packets. Any other type will be dropped with a warning msg.
+**
+** Parameters:
+** rconn - the new connection
+** client - list of files available to this host
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - If this is a valid boot request, it will be added to
+** the linked list of outstanding requests (RmpConns).
+** - If this is a valid boot complete, its associated
+** entry in RmpConns will be deleted.
+** - Also, unless we run out of memory, a reply will be
+** sent to the host that sent the packet.
+*/
+void
+ProcessPacket(rconn, client)
+ RMPCONN *rconn;
+ CLIENT *client;
+{
+ struct rmp_packet *rmp;
+ RMPCONN *rconnout;
+
+ rmp = &rconn->rmp; /* cache pointer to RMP packet */
+
+ switch(rmp->r_type) { /* do what we came here to do */
+ case RMP_BOOT_REQ: /* boot request */
+ if ((rconnout = NewConn(rconn)) == NULL)
+ return;
+
+ /*
+ * If the Session ID is 0xffff, this is a "probe"
+ * packet and we do not want to add the connection
+ * to the linked list of active connections. There
+ * are two types of probe packets, if the Sequence
+ * Number is 0 they want to know our host name, o/w
+ * they want the name of the file associated with
+ * the number spec'd by the Sequence Number.
+ *
+ * If this is an actual boot request, open the file
+ * and send a reply. If SendBootRepl() does not
+ * return 0, add the connection to the linked list
+ * of active connections, otherwise delete it since
+ * an error was encountered.
+ */
+ if (rmp->r_brq.rmp_session == RMP_PROBESID) {
+ if (WORDZE(rmp->r_brq.rmp_seqno))
+ (void) SendServerID(rconnout);
+ else
+ (void) SendFileNo(rmp, rconnout,
+ client? client->files:
+ BootFiles);
+ FreeConn(rconnout);
+ } else {
+ if (SendBootRepl(rmp, rconnout,
+ client? client->files: BootFiles))
+ AddConn(rconnout);
+ else
+ FreeConn(rconnout);
+ }
+ break;
+
+ case RMP_BOOT_REPL: /* boot reply (not valid) */
+ syslog(LOG_WARNING, "%s: sent a boot reply",
+ EnetStr(rconn));
+ break;
+
+ case RMP_READ_REQ: /* read request */
+ /*
+ * Send a portion of the boot file.
+ */
+ (void) SendReadRepl(rconn);
+ break;
+
+ case RMP_READ_REPL: /* read reply (not valid) */
+ syslog(LOG_WARNING, "%s: sent a read reply",
+ EnetStr(rconn));
+ break;
+
+ case RMP_BOOT_DONE: /* boot complete */
+ /*
+ * Remove the entry from the linked list of active
+ * connections.
+ */
+ (void) BootDone(rconn);
+ break;
+
+ default: /* unknown RMP packet type */
+ syslog(LOG_WARNING, "%s: unknown packet type (%u)",
+ EnetStr(rconn), rmp->r_type);
+ }
+}
+
+/*
+** SendServerID -- send our host name to who ever requested it.
+**
+** Parameters:
+** rconn - the reply packet to be formatted.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendServerID(rconn)
+ RMPCONN *rconn;
+{
+ register struct rmp_packet *rpl;
+ register char *src, *dst;
+ register u_char *size;
+
+ rpl = &rconn->rmp; /* cache ptr to RMP packet */
+
+ /*
+ * Set up assorted fields in reply packet.
+ */
+ rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
+ rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
+ ZEROWORD(rpl->r_brpl.rmp_seqno);
+ rpl->r_brpl.rmp_session = 0;
+ rpl->r_brpl.rmp_version = RMP_VERSION;
+
+ size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of host name */
+
+ /*
+ * Copy our host name into the reply packet incrementing the
+ * length as we go. Stop at RMP_HOSTLEN or the first dot.
+ */
+ src = MyHost;
+ dst = (char *) &rpl->r_brpl.rmp_flnm;
+ for (*size = 0; *size < RMP_HOSTLEN; (*size)++) {
+ if (*src == '.' || *src == '\0')
+ break;
+ *dst++ = *src++;
+ }
+
+ rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */
+
+ return(SendPacket(rconn)); /* send packet */
+}
+
+/*
+** SendFileNo -- send the name of a bootable file to the requester.
+**
+** Parameters:
+** req - RMP BOOT packet containing the request.
+** rconn - the reply packet to be formatted.
+** filelist - list of files available to the requester.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendFileNo(req, rconn, filelist)
+ struct rmp_packet *req;
+ RMPCONN *rconn;
+ char *filelist[];
+{
+ register struct rmp_packet *rpl;
+ register char *src, *dst;
+ register u_char *size, i;
+
+ GETWORD(req->r_brpl.rmp_seqno, i); /* SeqNo is really FileNo */
+ rpl = &rconn->rmp; /* cache ptr to RMP packet */
+
+ /*
+ * Set up assorted fields in reply packet.
+ */
+ rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
+ PUTWORD(i, rpl->r_brpl.rmp_seqno);
+ i--;
+ rpl->r_brpl.rmp_session = 0;
+ rpl->r_brpl.rmp_version = RMP_VERSION;
+
+ size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of filename */
+ *size = 0; /* init length to zero */
+
+ /*
+ * Copy the file name into the reply packet incrementing the
+ * length as we go. Stop at end of string or when RMPBOOTDATA
+ * characters have been copied. Also, set return code to
+ * indicate success or "no more files".
+ */
+ if (i < C_MAXFILE && filelist[i] != NULL) {
+ src = filelist[i];
+ dst = (char *)&rpl->r_brpl.rmp_flnm;
+ for (; *src && *size < RMPBOOTDATA; (*size)++) {
+ if (*src == '\0')
+ break;
+ *dst++ = *src++;
+ }
+ rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
+ } else
+ rpl->r_brpl.rmp_retcode = RMP_E_NODFLT;
+
+ rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */
+
+ return(SendPacket(rconn)); /* send packet */
+}
+
+/*
+** SendBootRepl -- open boot file and respond to boot request.
+**
+** Parameters:
+** req - RMP BOOT packet containing the request.
+** rconn - the reply packet to be formatted.
+** filelist - list of files available to the requester.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendBootRepl(req, rconn, filelist)
+ struct rmp_packet *req;
+ RMPCONN *rconn;
+ char *filelist[];
+{
+ int retval;
+ char *filename, filepath[RMPBOOTDATA+1];
+ RMPCONN *oldconn;
+ register struct rmp_packet *rpl;
+ register char *src, *dst1, *dst2;
+ register u_char i;
+
+ /*
+ * If another connection already exists, delete it since we
+ * are obviously starting again.
+ */
+ if ((oldconn = FindConn(rconn)) != NULL) {
+ syslog(LOG_WARNING, "%s: dropping existing connection",
+ EnetStr(oldconn));
+ RemoveConn(oldconn);
+ }
+
+ rpl = &rconn->rmp; /* cache ptr to RMP packet */
+
+ /*
+ * Set up assorted fields in reply packet.
+ */
+ rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
+ COPYWORD(req->r_brq.rmp_seqno, rpl->r_brpl.rmp_seqno);
+ rpl->r_brpl.rmp_session = GenSessID();
+ rpl->r_brpl.rmp_version = RMP_VERSION;
+ rpl->r_brpl.rmp_flnmsize = req->r_brq.rmp_flnmsize;
+
+ /*
+ * Copy file name to `filepath' string, and into reply packet.
+ */
+ src = &req->r_brq.rmp_flnm;
+ dst1 = filepath;
+ dst2 = &rpl->r_brpl.rmp_flnm;
+ for (i = 0; i < req->r_brq.rmp_flnmsize; i++)
+ *dst1++ = *dst2++ = *src++;
+ *dst1 = '\0';
+
+ /*
+ * If we are booting HP-UX machines, their secondary loader will
+ * ask for files like "/hp-ux". As a security measure, we do not
+ * allow boot files to lay outside the boot directory (unless they
+ * are purposely link'd out. So, make `filename' become the path-
+ * stripped file name and spoof the client into thinking that it
+ * really got what it wanted.
+ */
+ filename = (filename = rindex(filepath,'/'))? ++filename: filepath;
+
+ /*
+ * Check that this is a valid boot file name.
+ */
+ for (i = 0; i < C_MAXFILE && filelist[i] != NULL; i++)
+ if (STREQN(filename, filelist[i]))
+ goto match;
+
+ /*
+ * Invalid boot file name, set error and send reply packet.
+ */
+ rpl->r_brpl.rmp_retcode = RMP_E_NOFILE;
+ retval = 0;
+ goto sendpkt;
+
+match:
+ /*
+ * This is a valid boot file. Open the file and save the file
+ * descriptor associated with this connection and set success
+ * indication. If the file couldnt be opened, set error:
+ * "no such file or dir" - RMP_E_NOFILE
+ * "file table overflow" - RMP_E_BUSY
+ * "too many open files" - RMP_E_BUSY
+ * anything else - RMP_E_OPENFILE
+ */
+ if ((rconn->bootfd = open(filename, O_RDONLY, 0600)) < 0) {
+ rpl->r_brpl.rmp_retcode = (errno == ENOENT)? RMP_E_NOFILE:
+ (errno == EMFILE || errno == ENFILE)? RMP_E_BUSY:
+ RMP_E_OPENFILE;
+ retval = 0;
+ } else {
+ rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
+ retval = 1;
+ }
+
+sendpkt:
+ syslog(LOG_INFO, "%s: request to boot %s (%s)",
+ EnetStr(rconn), filename, retval? "granted": "denied");
+
+ rconn->rmplen = RMPBOOTSIZE(rpl->r_brpl.rmp_flnmsize);
+
+ return (retval & SendPacket(rconn));
+}
+
+/*
+** SendReadRepl -- send a portion of the boot file to the requester.
+**
+** Parameters:
+** rconn - the reply packet to be formatted.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendReadRepl(rconn)
+ RMPCONN *rconn;
+{
+ int retval;
+ RMPCONN *oldconn;
+ register struct rmp_packet *rpl, *req;
+ register int size = 0;
+ int madeconn = 0;
+
+ /*
+ * Find the old connection. If one doesnt exist, create one only
+ * to return the error code.
+ */
+ if ((oldconn = FindConn(rconn)) == NULL) {
+ if ((oldconn = NewConn(rconn)) == NULL)
+ return(0);
+ syslog(LOG_ERR, "SendReadRepl: no active connection (%s)",
+ EnetStr(rconn));
+ madeconn++;
+ }
+
+ req = &rconn->rmp; /* cache ptr to request packet */
+ rpl = &oldconn->rmp; /* cache ptr to reply packet */
+
+ if (madeconn) { /* no active connection above; abort */
+ rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
+ retval = 1;
+ goto sendpkt;
+ }
+
+ /*
+ * Make sure Session ID's match.
+ */
+ if (req->r_rrq.rmp_session !=
+ ((rpl->r_type == RMP_BOOT_REPL)? rpl->r_brpl.rmp_session:
+ rpl->r_rrpl.rmp_session)) {
+ syslog(LOG_ERR, "SendReadRepl: bad session id (%s)",
+ EnetStr(rconn));
+ rpl->r_rrpl.rmp_retcode = RMP_E_BADSID;
+ retval = 1;
+ goto sendpkt;
+ }
+
+ /*
+ * If the requester asks for more data than we can fit,
+ * silently clamp the request size down to RMPREADDATA.
+ *
+ * N.B. I do not know if this is "legal", however it seems
+ * to work. This is necessary for bpfwrite() on machines
+ * with MCLBYTES less than 1514.
+ */
+ if (req->r_rrq.rmp_size > RMPREADDATA)
+ req->r_rrq.rmp_size = RMPREADDATA;
+
+ /*
+ * Position read head on file according to info in request packet.
+ */
+ GETWORD(req->r_rrq.rmp_offset, size);
+ if (lseek(oldconn->bootfd, (off_t)size, L_SET) < 0) {
+ syslog(LOG_ERR, "SendReadRepl: lseek: %m (%s)",
+ EnetStr(rconn));
+ rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
+ retval = 1;
+ goto sendpkt;
+ }
+
+ /*
+ * Read data directly into reply packet.
+ */
+ if ((size = read(oldconn->bootfd, &rpl->r_rrpl.rmp_data,
+ (int) req->r_rrq.rmp_size)) <= 0) {
+ if (size < 0) {
+ syslog(LOG_ERR, "SendReadRepl: read: %m (%s)",
+ EnetStr(rconn));
+ rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
+ } else {
+ rpl->r_rrpl.rmp_retcode = RMP_E_EOF;
+ }
+ retval = 1;
+ goto sendpkt;
+ }
+
+ /*
+ * Set success indication.
+ */
+ rpl->r_rrpl.rmp_retcode = RMP_E_OKAY;
+
+sendpkt:
+ /*
+ * Set up assorted fields in reply packet.
+ */
+ rpl->r_rrpl.rmp_type = RMP_READ_REPL;
+ COPYWORD(req->r_rrq.rmp_offset, rpl->r_rrpl.rmp_offset);
+ rpl->r_rrpl.rmp_session = req->r_rrq.rmp_session;
+
+ oldconn->rmplen = RMPREADSIZE(size); /* set size of packet */
+
+ retval &= SendPacket(oldconn); /* send packet */
+
+ if (madeconn) /* clean up after ourself */
+ FreeConn(oldconn);
+
+ return (retval);
+}
+
+/*
+** BootDone -- free up memory allocated for a connection.
+**
+** Parameters:
+** rconn - incoming boot complete packet.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+BootDone(rconn)
+ RMPCONN *rconn;
+{
+ RMPCONN *oldconn;
+ struct rmp_packet *rpl;
+
+ /*
+ * If we cant find the connection, ignore the request.
+ */
+ if ((oldconn = FindConn(rconn)) == NULL) {
+ syslog(LOG_ERR, "BootDone: no existing connection (%s)",
+ EnetStr(rconn));
+ return(0);
+ }
+
+ rpl = &oldconn->rmp; /* cache ptr to RMP packet */
+
+ /*
+ * Make sure Session ID's match.
+ */
+ if (rconn->rmp.r_rrq.rmp_session !=
+ ((rpl->r_type == RMP_BOOT_REPL)? rpl->r_brpl.rmp_session:
+ rpl->r_rrpl.rmp_session)) {
+ syslog(LOG_ERR, "BootDone: bad session id (%s)",
+ EnetStr(rconn));
+ return(0);
+ }
+
+ RemoveConn(oldconn); /* remove connection */
+
+ syslog(LOG_INFO, "%s: boot complete", EnetStr(rconn));
+
+ return(1);
+}
+
+/*
+** SendPacket -- send an RMP packet to a remote host.
+**
+** Parameters:
+** rconn - packet to be sent.
+**
+** Returns:
+** 1 on success, 0 on failure.
+**
+** Side Effects:
+** none.
+*/
+int
+SendPacket(rconn)
+ register RMPCONN *rconn;
+{
+ /*
+ * Set Ethernet Destination address to Source (BPF and the enet
+ * driver will take care of getting our source address set).
+ */
+ bcopy((char *)&rconn->rmp.hp_hdr.saddr[0],
+ (char *)&rconn->rmp.hp_hdr.daddr[0], RMP_ADDRLEN);
+ rconn->rmp.hp_hdr.len = rconn->rmplen - sizeof(struct hp_hdr);
+
+ /*
+ * Reverse 802.2/HP Extended Source & Destination Access Pts.
+ */
+ rconn->rmp.hp_llc.dxsap = HPEXT_SXSAP;
+ rconn->rmp.hp_llc.sxsap = HPEXT_DXSAP;
+
+ /*
+ * Last time this connection was active.
+ */
+ (void) gettimeofday(&rconn->tstamp, (struct timezone *)0);
+
+ if (DbgFp != NULL) /* display packet */
+ DispPkt(rconn,DIR_SENT);
+
+ /*
+ * Send RMP packet to remote host.
+ */
+ return(BpfWrite(rconn));
+}
diff --git a/libexec/rbootd/utils.c b/libexec/rbootd/utils.c
new file mode 100644
index 0000000..58ead7c
--- /dev/null
+++ b/libexec/rbootd/utils.c
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 1988, 1992 The University of Utah and the Center
+ * for Software Science (CSS).
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Center for Software Science of the University of Utah Computer
+ * Science Department. CSS requests users of this software to return
+ * to css-dist@cs.utah.edu any improvements that they make and grant
+ * CSS redistribution rights.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)utils.c 8.2 (Berkeley) 2/22/94
+ *
+ * Utah $Hdr: utils.c 3.1 92/07/06$
+ * Author: Jeff Forys, University of Utah CSS
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)utils.c 8.2 (Berkeley) 2/22/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+#include "defs.h"
+
+/*
+** DispPkt -- Display the contents of an RMPCONN packet.
+**
+** Parameters:
+** rconn - packet to be displayed.
+** direct - direction packet is going (DIR_*).
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** None.
+*/
+void
+DispPkt(rconn, direct)
+ RMPCONN *rconn;
+ int direct;
+{
+ static char BootFmt[] = "\t\tRetCode:%u SeqNo:%lx SessID:%x Vers:%u";
+ static char ReadFmt[] = "\t\tRetCode:%u Offset:%lx SessID:%x\n";
+
+ struct tm *tmp;
+ register struct rmp_packet *rmp;
+ int i, omask;
+ u_int t;
+
+ /*
+ * Since we will be working with RmpConns as well as DbgFp, we
+ * must block signals that can affect either.
+ */
+ omask = sigblock(sigmask(SIGHUP)|sigmask(SIGUSR1)|sigmask(SIGUSR2));
+
+ if (DbgFp == NULL) { /* sanity */
+ (void) sigsetmask(omask);
+ return;
+ }
+
+ /* display direction packet is going using '>>>' or '<<<' */
+ fputs((direct==DIR_RCVD)?"<<< ":(direct==DIR_SENT)?">>> ":"", DbgFp);
+
+ /* display packet timestamp */
+ tmp = localtime((time_t *)&rconn->tstamp.tv_sec);
+ fprintf(DbgFp, "%02d:%02d:%02d.%06ld ", tmp->tm_hour, tmp->tm_min,
+ tmp->tm_sec, rconn->tstamp.tv_usec);
+
+ /* display src or dst addr and information about network interface */
+ fprintf(DbgFp, "Addr: %s Intf: %s\n", EnetStr(rconn), IntfName);
+
+ rmp = &rconn->rmp;
+
+ /* display IEEE 802.2 Logical Link Control header */
+ (void) fprintf(DbgFp, "\t802.2 LLC: DSAP:%x SSAP:%x CTRL:%x\n",
+ rmp->hp_llc.dsap, rmp->hp_llc.ssap, rmp->hp_llc.cntrl);
+
+ /* display HP extensions to 802.2 Logical Link Control header */
+ (void) fprintf(DbgFp, "\tHP Ext: DXSAP:%x SXSAP:%x\n",
+ rmp->hp_llc.dxsap, rmp->hp_llc.sxsap);
+
+ /*
+ * Display information about RMP packet using type field to
+ * determine what kind of packet this is.
+ */
+ switch(rmp->r_type) {
+ case RMP_BOOT_REQ: /* boot request */
+ (void) fprintf(DbgFp, "\tBoot Request:");
+ GETWORD(rmp->r_brq.rmp_seqno, t);
+ if (rmp->r_brq.rmp_session == RMP_PROBESID) {
+ if (WORDZE(rmp->r_brq.rmp_seqno))
+ fputs(" (Send Server ID)", DbgFp);
+ else
+ fprintf(DbgFp," (Send Filename #%u)",t);
+ }
+ (void) fputc('\n', DbgFp);
+ (void) fprintf(DbgFp, BootFmt, rmp->r_brq.rmp_retcode,
+ t, rmp->r_brq.rmp_session,
+ rmp->r_brq.rmp_version);
+ (void) fprintf(DbgFp, "\n\t\tMachine Type: ");
+ for (i = 0; i < RMP_MACHLEN; i++)
+ (void) fputc(rmp->r_brq.rmp_machtype[i], DbgFp);
+ DspFlnm(rmp->r_brq.rmp_flnmsize, &rmp->r_brq.rmp_flnm);
+ break;
+ case RMP_BOOT_REPL: /* boot reply */
+ fprintf(DbgFp, "\tBoot Reply:\n");
+ GETWORD(rmp->r_brpl.rmp_seqno, t);
+ (void) fprintf(DbgFp, BootFmt, rmp->r_brpl.rmp_retcode,
+ t, rmp->r_brpl.rmp_session,
+ rmp->r_brpl.rmp_version);
+ DspFlnm(rmp->r_brpl.rmp_flnmsize,&rmp->r_brpl.rmp_flnm);
+ break;
+ case RMP_READ_REQ: /* read request */
+ (void) fprintf(DbgFp, "\tRead Request:\n");
+ GETWORD(rmp->r_rrq.rmp_offset, t);
+ (void) fprintf(DbgFp, ReadFmt, rmp->r_rrq.rmp_retcode,
+ t, rmp->r_rrq.rmp_session);
+ (void) fprintf(DbgFp, "\t\tNoOfBytes: %u\n",
+ rmp->r_rrq.rmp_size);
+ break;
+ case RMP_READ_REPL: /* read reply */
+ (void) fprintf(DbgFp, "\tRead Reply:\n");
+ GETWORD(rmp->r_rrpl.rmp_offset, t);
+ (void) fprintf(DbgFp, ReadFmt, rmp->r_rrpl.rmp_retcode,
+ t, rmp->r_rrpl.rmp_session);
+ (void) fprintf(DbgFp, "\t\tNoOfBytesSent: %d\n",
+ rconn->rmplen - RMPREADSIZE(0));
+ break;
+ case RMP_BOOT_DONE: /* boot complete */
+ (void) fprintf(DbgFp, "\tBoot Complete:\n");
+ (void) fprintf(DbgFp, "\t\tRetCode:%u SessID:%x\n",
+ rmp->r_done.rmp_retcode,
+ rmp->r_done.rmp_session);
+ break;
+ default: /* ??? */
+ (void) fprintf(DbgFp, "\tUnknown Type:(%d)\n",
+ rmp->r_type);
+ }
+ (void) fputc('\n', DbgFp);
+ (void) fflush(DbgFp);
+
+ (void) sigsetmask(omask); /* reset old signal mask */
+}
+
+
+/*
+** GetEtherAddr -- convert an RMP (Ethernet) address into a string.
+**
+** An RMP BOOT packet has been received. Look at the type field
+** and process Boot Requests, Read Requests, and Boot Complete
+** packets. Any other type will be dropped with a warning msg.
+**
+** Parameters:
+** addr - array of RMP_ADDRLEN bytes.
+**
+** Returns:
+** Pointer to static string representation of `addr'.
+**
+** Side Effects:
+** None.
+**
+** Warnings:
+** - The return value points to a static buffer; it must
+** be copied if it's to be saved.
+** - For speed, we assume a u_char consists of 8 bits.
+*/
+char *
+GetEtherAddr(addr)
+ u_char *addr;
+{
+ static char Hex[] = "0123456789abcdef";
+ static char etherstr[RMP_ADDRLEN*3];
+ register int i;
+ register char *cp1, *cp2;
+
+ /*
+ * For each byte in `addr', convert it to "<hexchar><hexchar>:".
+ * The last byte does not get a trailing `:' appended.
+ */
+ i = 0;
+ cp1 = (char *)addr;
+ cp2 = etherstr;
+ for(;;) {
+ *cp2++ = Hex[*cp1 >> 4 & 0xf];
+ *cp2++ = Hex[*cp1++ & 0xf];
+ if (++i == RMP_ADDRLEN)
+ break;
+ *cp2++ = ':';
+ }
+ *cp2 = '\0';
+
+ return(etherstr);
+}
+
+
+/*
+** DispFlnm -- Print a string of bytes to DbgFp (often, a file name).
+**
+** Parameters:
+** size - number of bytes to print.
+** flnm - address of first byte.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Characters are sent to `DbgFp'.
+*/
+void
+DspFlnm(size, flnm)
+ register u_int size;
+ register char *flnm;
+{
+ register int i;
+
+ (void) fprintf(DbgFp, "\n\t\tFile Name (%d): <", size);
+ for (i = 0; i < size; i++)
+ (void) fputc(*flnm++, DbgFp);
+ (void) fputs(">\n", DbgFp);
+}
+
+
+/*
+** NewClient -- allocate memory for a new CLIENT.
+**
+** Parameters:
+** addr - RMP (Ethernet) address of new client.
+**
+** Returns:
+** Ptr to new CLIENT or NULL if we ran out of memory.
+**
+** Side Effects:
+** - Memory will be malloc'd for the new CLIENT.
+** - If malloc() fails, a log message will be generated.
+*/
+CLIENT *
+NewClient(addr)
+ u_char *addr;
+{
+ CLIENT *ctmp;
+
+ if ((ctmp = (CLIENT *) malloc(sizeof(CLIENT))) == NULL) {
+ syslog(LOG_ERR, "NewClient: out of memory (%s)",
+ GetEtherAddr(addr));
+ return(NULL);
+ }
+
+ bzero(ctmp, sizeof(CLIENT));
+ bcopy(addr, &ctmp->addr[0], RMP_ADDRLEN);
+ return(ctmp);
+}
+
+/*
+** FreeClient -- free linked list of Clients.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - All malloc'd memory associated with the linked list of
+** CLIENTS will be free'd; `Clients' will be set to NULL.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+FreeClients()
+{
+ register CLIENT *ctmp;
+
+ while (Clients != NULL) {
+ ctmp = Clients;
+ Clients = Clients->next;
+ FreeClient(ctmp);
+ }
+}
+
+/*
+** NewStr -- allocate memory for a character array.
+**
+** Parameters:
+** str - null terminated character array.
+**
+** Returns:
+** Ptr to new character array or NULL if we ran out of memory.
+**
+** Side Effects:
+** - Memory will be malloc'd for the new character array.
+** - If malloc() fails, a log message will be generated.
+*/
+char *
+NewStr(str)
+ char *str;
+{
+ char *stmp;
+
+ if ((stmp = (char *)malloc((unsigned) (strlen(str)+1))) == NULL) {
+ syslog(LOG_ERR, "NewStr: out of memory (%s)", str);
+ return(NULL);
+ }
+
+ (void) strcpy(stmp, str);
+ return(stmp);
+}
+
+/*
+** To save time, NewConn and FreeConn maintain a cache of one RMPCONN
+** in `LastFree' (defined below).
+*/
+
+static RMPCONN *LastFree = NULL;
+
+/*
+** NewConn -- allocate memory for a new RMPCONN connection.
+**
+** Parameters:
+** rconn - initialization template for new connection.
+**
+** Returns:
+** Ptr to new RMPCONN or NULL if we ran out of memory.
+**
+** Side Effects:
+** - Memory may be malloc'd for the new RMPCONN (if not cached).
+** - If malloc() fails, a log message will be generated.
+*/
+RMPCONN *
+NewConn(rconn)
+ RMPCONN *rconn;
+{
+ RMPCONN *rtmp;
+
+ if (LastFree == NULL) { /* nothing cached; make a new one */
+ if ((rtmp = (RMPCONN *) malloc(sizeof(RMPCONN))) == NULL) {
+ syslog(LOG_ERR, "NewConn: out of memory (%s)",
+ EnetStr(rconn));
+ return(NULL);
+ }
+ } else { /* use the cached RMPCONN */
+ rtmp = LastFree;
+ LastFree = NULL;
+ }
+
+ /*
+ * Copy template into `rtmp', init file descriptor to `-1' and
+ * set ptr to next elem NULL.
+ */
+ bcopy((char *)rconn, (char *)rtmp, sizeof(RMPCONN));
+ rtmp->bootfd = -1;
+ rtmp->next = NULL;
+
+ return(rtmp);
+}
+
+/*
+** FreeConn -- Free memory associated with an RMPCONN connection.
+**
+** Parameters:
+** rtmp - ptr to RMPCONN to be free'd.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - Memory associated with `rtmp' may be free'd (or cached).
+** - File desc associated with `rtmp->bootfd' will be closed.
+*/
+void
+FreeConn(rtmp)
+ register RMPCONN *rtmp;
+{
+ /*
+ * If the file descriptor is in use, close the file.
+ */
+ if (rtmp->bootfd >= 0) {
+ (void) close(rtmp->bootfd);
+ rtmp->bootfd = -1;
+ }
+
+ if (LastFree == NULL) /* cache for next time */
+ rtmp = LastFree;
+ else /* already one cached; free this one */
+ free((char *)rtmp);
+}
+
+/*
+** FreeConns -- free linked list of RMPCONN connections.
+**
+** Parameters:
+** None.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - All malloc'd memory associated with the linked list of
+** connections will be free'd; `RmpConns' will be set to NULL.
+** - If LastFree is != NULL, it too will be free'd & NULL'd.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+FreeConns()
+{
+ register RMPCONN *rtmp;
+
+ while (RmpConns != NULL) {
+ rtmp = RmpConns;
+ RmpConns = RmpConns->next;
+ FreeConn(rtmp);
+ }
+
+ if (LastFree != NULL) {
+ free((char *)LastFree);
+ LastFree = NULL;
+ }
+}
+
+/*
+** AddConn -- Add a connection to the linked list of connections.
+**
+** Parameters:
+** rconn - connection to be added.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - RmpConn will point to new connection.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+AddConn(rconn)
+ register RMPCONN *rconn;
+{
+ if (RmpConns != NULL)
+ rconn->next = RmpConns;
+ RmpConns = rconn;
+}
+
+/*
+** FindConn -- Find a connection in the linked list of connections.
+**
+** We use the RMP (Ethernet) address as the basis for determining
+** if this is the same connection. According to the Remote Maint
+** Protocol, we can only have one connection with any machine.
+**
+** Parameters:
+** rconn - connection to be found.
+**
+** Returns:
+** Matching connection from linked list or NULL if not found.
+**
+** Side Effects:
+** None.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+RMPCONN *
+FindConn(rconn)
+ register RMPCONN *rconn;
+{
+ register RMPCONN *rtmp;
+
+ for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
+ if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
+ (char *)&rtmp->rmp.hp_hdr.saddr[0], RMP_ADDRLEN) == 0)
+ break;
+
+ return(rtmp);
+}
+
+/*
+** RemoveConn -- Remove a connection from the linked list of connections.
+**
+** Parameters:
+** rconn - connection to be removed.
+**
+** Returns:
+** Nothing.
+**
+** Side Effects:
+** - If found, an RMPCONN will cease to exist and it will
+** be removed from the linked list.
+**
+** Warnings:
+** - This routine must be called with SIGHUP blocked.
+*/
+void
+RemoveConn(rconn)
+ register RMPCONN *rconn;
+{
+ register RMPCONN *thisrconn, *lastrconn;
+
+ if (RmpConns == rconn) { /* easy case */
+ RmpConns = RmpConns->next;
+ FreeConn(rconn);
+ } else { /* must traverse linked list */
+ lastrconn = RmpConns; /* set back ptr */
+ thisrconn = lastrconn->next; /* set current ptr */
+ while (thisrconn != NULL) {
+ if (rconn == thisrconn) { /* found it */
+ lastrconn->next = thisrconn->next;
+ FreeConn(thisrconn);
+ break;
+ }
+ lastrconn = thisrconn;
+ thisrconn = thisrconn->next;
+ }
+ }
+}
OpenPOWER on IntegriCloud