Original version from 4.4BSD/Utah.

This commit is contained in:
brezak 1994-01-11 15:43:38 +00:00
parent 07a07b09a6
commit e05cab76da
12 changed files with 3269 additions and 0 deletions

11
usr.sbin/rbootd/Makefile Normal file
View File

@ -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>

422
usr.sbin/rbootd/bpf.c Normal file
View File

@ -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;
}

90
usr.sbin/rbootd/conf.c Normal file
View File

@ -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 */

185
usr.sbin/rbootd/defs.h Normal file
View File

@ -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 *));

359
usr.sbin/rbootd/parseconf.c Normal file
View File

@ -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);
}

View File

@ -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"

156
usr.sbin/rbootd/rbootd.8 Normal file
View File

@ -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.

507
usr.sbin/rbootd/rbootd.c Normal file
View File

@ -0,0 +1,507 @@
/*
* 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.1 (Berkeley) 6/4/93
*
* 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.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/param.h>
#include <sys/ioctl.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);
}
}

95
usr.sbin/rbootd/rmp.h Normal file
View File

@ -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 */
};

244
usr.sbin/rbootd/rmp_var.h Normal file
View File

@ -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

593
usr.sbin/rbootd/rmpproto.c Normal file
View File

@ -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));
}

556
usr.sbin/rbootd/utils.c Normal file
View File

@ -0,0 +1,556 @@
/*
* 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.1 (Berkeley) 6/4/93
*
* Utah $Hdr: utils.c 3.1 92/07/06$
* Author: Jeff Forys, University of Utah CSS
*/
#ifndef lint
static char sccsid[] = "@(#)utils.c 8.1 (Berkeley) 6/4/93";
#endif /* not lint */
#include <sys/param.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;
}
}
}