11541Srgrimes/*
21541Srgrimes * Copyright (c) 1988, 1992 The University of Utah and the Center
31541Srgrimes *	for Software Science (CSS).
41541Srgrimes * Copyright (c) 1992, 1993
51541Srgrimes *	The Regents of the University of California.  All rights reserved.
61541Srgrimes *
71541Srgrimes * This code is derived from software contributed to Berkeley by
81541Srgrimes * the Center for Software Science of the University of Utah Computer
91541Srgrimes * Science Department.  CSS requests users of this software to return
101541Srgrimes * to css-dist@cs.utah.edu any improvements that they make and grant
111541Srgrimes * CSS redistribution rights.
121541Srgrimes *
131541Srgrimes * Redistribution and use in source and binary forms, with or without
141541Srgrimes * modification, are permitted provided that the following conditions
151541Srgrimes * are met:
161541Srgrimes * 1. Redistributions of source code must retain the above copyright
171541Srgrimes *    notice, this list of conditions and the following disclaimer.
181541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
191541Srgrimes *    notice, this list of conditions and the following disclaimer in the
201541Srgrimes *    documentation and/or other materials provided with the distribution.
211541Srgrimes * 3. Neither the name of the University nor the names of its contributors
221541Srgrimes *    may be used to endorse or promote products derived from this software
231541Srgrimes *    without specific prior written permission.
241541Srgrimes *
251541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351541Srgrimes * SUCH DAMAGE.
3636503Speter *
371541Srgrimes *	from: @(#)rmpproto.c	8.1 (Berkeley) 6/4/93
381541Srgrimes *
3983651Speter * From: Utah Hdr: rmpproto.c 3.1 92/07/06
4083651Speter * Author: Jeff Forys, University of Utah CSS
4183651Speter */
421541Srgrimes
431541Srgrimes#ifndef lint
441541Srgrimes#if 0
451541Srgrimesstatic const char sccsid[] = "@(#)rmpproto.c	8.1 (Berkeley) 6/4/93";
461541Srgrimes#endif
4783651Speterstatic const char rcsid[] =
481541Srgrimes  "$FreeBSD: releng/11.0/libexec/rbootd/rmpproto.c 262136 2014-02-17 22:27:32Z brueffer $";
4948274Speter#endif /* not lint */
5048274Speter
5160041Sphk#include <sys/param.h>
5231886Sbde#include <sys/time.h>
531541Srgrimes#include <netinet/in.h>
541541Srgrimes
551541Srgrimes#include <errno.h>
561541Srgrimes#include <fcntl.h>
571541Srgrimes#include <stdio.h>
581541Srgrimes#include <string.h>
591541Srgrimes#include <syslog.h>
609336Sdfr#include <unistd.h>
612997Swollman#include "defs.h"
622997Swollman
6383651Speter/*
641541Srgrimes**  ProcessPacket -- determine packet type and do what's required.
653305Sphk**
6612662Sdg**	An RMP BOOT packet has been received.  Look at the type field
6712662Sdg**	and process Boot Requests, Read Requests, and Boot Complete
6892783Sjeff**	packets.  Any other type will be dropped with a warning msg.
693305Sphk**
701541Srgrimes**	Parameters:
719336Sdfr**		rconn - the new connection
7283651Speter**		client - list of files available to this host
7383651Speter**
741541Srgrimes**	Returns:
7583651Speter**		Nothing.
7683651Speter**
771541Srgrimes**	Side Effects:
781541Srgrimes**		- If this is a valid boot request, it will be added to
791541Srgrimes**		  the linked list of outstanding requests (RmpConns).
801541Srgrimes**		- If this is a valid boot complete, its associated
811541Srgrimes**		  entry in RmpConns will be deleted.
821541Srgrimes**		- Also, unless we run out of memory, a reply will be
831541Srgrimes**		  sent to the host that sent the packet.
8483651Speter*/
8583651Spetervoid
8683651SpeterProcessPacket(RMPCONN *rconn, CLIENT *client)
8783651Speter{
881541Srgrimes	struct rmp_packet *rmp;
891541Srgrimes	RMPCONN *rconnout;
9036541Speter
9112911Sphk	rmp = &rconn->rmp;		/* cache pointer to RMP packet */
9283651Speter
9312911Sphk	switch(rmp->r_type) {		/* do what we came here to do */
9412911Sphk		case RMP_BOOT_REQ:		/* boot request */
9583651Speter			if ((rconnout = NewConn(rconn)) == NULL)
9683651Speter				return;
979336Sdfr
9883651Speter			/*
9983651Speter			 *  If the Session ID is 0xffff, this is a "probe"
1009759Sbde			 *  packet and we do not want to add the connection
10183651Speter			 *  to the linked list of active connections.  There
10283651Speter			 *  are two types of probe packets, if the Sequence
10338894Sbde			 *  Number is 0 they want to know our host name, o/w
1049336Sdfr			 *  they want the name of the file associated with
1059336Sdfr			 *  the number spec'd by the Sequence Number.
1069336Sdfr			 *
1079336Sdfr			 *  If this is an actual boot request, open the file
1089336Sdfr			 *  and send a reply.  If SendBootRepl() does not
1099336Sdfr			 *  return 0, add the connection to the linked list
1109336Sdfr			 *  of active connections, otherwise delete it since
1119336Sdfr			 *  an error was encountered.
1129336Sdfr			 */
1139336Sdfr			if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) {
1149336Sdfr				if (WORDZE(rmp->r_brq.rmp_seqno))
1159336Sdfr					(void) SendServerID(rconnout);
1169336Sdfr				else
1179336Sdfr					(void) SendFileNo(rmp, rconnout,
1189336Sdfr					                  client? client->files:
1199336Sdfr					                          BootFiles);
1209336Sdfr				FreeConn(rconnout);
1219336Sdfr			} else {
1229336Sdfr				if (SendBootRepl(rmp, rconnout,
1239336Sdfr				    client? client->files: BootFiles))
1249336Sdfr					AddConn(rconnout);
1259336Sdfr				else
1269336Sdfr					FreeConn(rconnout);
1279336Sdfr			}
1289336Sdfr			break;
1299336Sdfr
1309336Sdfr		case RMP_BOOT_REPL:		/* boot reply (not valid) */
1319336Sdfr			syslog(LOG_WARNING, "%s: sent a boot reply",
1329336Sdfr			       EnetStr(rconn));
13360938Sjake			break;
1343664Sphk
1351541Srgrimes		case RMP_READ_REQ:		/* read request */
1361541Srgrimes			/*
1371541Srgrimes			 *  Send a portion of the boot file.
1381541Srgrimes			 */
1391541Srgrimes			(void) SendReadRepl(rconn);
1401541Srgrimes			break;
14183651Speter
1421541Srgrimes		case RMP_READ_REPL:		/* read reply (not valid) */
14383651Speter			syslog(LOG_WARNING, "%s: sent a read reply",
1441541Srgrimes			       EnetStr(rconn));
14570254Sbmilekic			break;
1461541Srgrimes
14770254Sbmilekic		case RMP_BOOT_DONE:		/* boot complete */
1481541Srgrimes			/*
1491541Srgrimes			 *  Remove the entry from the linked list of active
1501541Srgrimes			 *  connections.
1511541Srgrimes			 */
1521541Srgrimes			(void) BootDone(rconn);
1531541Srgrimes			break;
1541541Srgrimes
1551541Srgrimes		default:			/* unknown RMP packet type */
1561541Srgrimes			syslog(LOG_WARNING, "%s: unknown packet type (%u)",
1571541Srgrimes			       EnetStr(rconn), rmp->r_type);
1581541Srgrimes	}
15983651Speter}
16083651Speter
16183651Speter/*
1621541Srgrimes**  SendServerID -- send our host name to who ever requested it.
16383651Speter**
16483651Speter**	Parameters:
16583651Speter**		rconn - the reply packet to be formatted.
16683651Speter**
16783651Speter**	Returns:
16883651Speter**		1 on success, 0 on failure.
1691541Srgrimes**
1701541Srgrimes**	Side Effects:
17170254Sbmilekic**		none.
1729336Sdfr*/
17370254Sbmilekicint
1749336SdfrSendServerID(RMPCONN *rconn)
1759336Sdfr{
1761541Srgrimes	struct rmp_packet *rpl;
1779336Sdfr	char *src, *dst;
1781541Srgrimes	u_int8_t *size;
1791541Srgrimes
1801541Srgrimes	rpl = &rconn->rmp;			/* cache ptr to RMP packet */
1811541Srgrimes
1821541Srgrimes	/*
1831541Srgrimes	 *  Set up assorted fields in reply packet.
1841541Srgrimes	 */
1851541Srgrimes	rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
18684002Speter	rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
18717186Sdfr	ZEROWORD(rpl->r_brpl.rmp_seqno);
18835066Sphk	rpl->r_brpl.rmp_session = 0;
18983651Speter	rpl->r_brpl.rmp_version = htons(RMP_VERSION);
19035066Sphk
19117186Sdfr	size = &rpl->r_brpl.rmp_flnmsize;	/* ptr to length of host name */
19217186Sdfr
19317186Sdfr	/*
1941541Srgrimes	 *  Copy our host name into the reply packet incrementing the
1951541Srgrimes	 *  length as we go.  Stop at RMP_HOSTLEN or the first dot.
19617186Sdfr	 */
1971541Srgrimes	src = MyHost;
1981541Srgrimes	dst = (char *) &rpl->r_brpl.rmp_flnm;
1991541Srgrimes	for (*size = 0; *size < RMP_HOSTLEN; (*size)++) {
20083651Speter		if (*src == '.' || *src == '\0')
20183651Speter			break;
20283651Speter		*dst++ = *src++;
20383651Speter	}
2041541Srgrimes
20583651Speter	rconn->rmplen = RMPBOOTSIZE(*size);	/* set packet length */
20683651Speter
2071541Srgrimes	return(SendPacket(rconn));		/* send packet */
2081541Srgrimes}
2091541Srgrimes
2101541Srgrimes/*
2111541Srgrimes**  SendFileNo -- send the name of a bootable file to the requester.
2121541Srgrimes**
2131541Srgrimes**	Parameters:
2141541Srgrimes**		req - RMP BOOT packet containing the request.
2151541Srgrimes**		rconn - the reply packet to be formatted.
21684002Speter**		filelist - list of files available to the requester.
2171541Srgrimes**
2181541Srgrimes**	Returns:
2191541Srgrimes**		1 on success, 0 on failure.
2201541Srgrimes**
2211541Srgrimes**	Side Effects:
2221541Srgrimes**		none.
2231541Srgrimes*/
2241541Srgrimesint
2251541SrgrimesSendFileNo(struct rmp_packet *req, RMPCONN *rconn, char *filelist[])
22683651Speter{
2279336Sdfr	struct rmp_packet *rpl;
2289336Sdfr	char *src, *dst;
2299336Sdfr	u_int8_t *size;
2309336Sdfr	int i;
23184002Speter
23283651Speter	GETWORD(req->r_brpl.rmp_seqno, i);	/* SeqNo is really FileNo */
23383651Speter	rpl = &rconn->rmp;			/* cache ptr to RMP packet */
2341541Srgrimes
2359336Sdfr	/*
2361541Srgrimes	 *  Set up assorted fields in reply packet.
2371541Srgrimes	 */
2381541Srgrimes	rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
2391541Srgrimes	PUTWORD(i, rpl->r_brpl.rmp_seqno);
2401541Srgrimes	i--;
2411541Srgrimes	rpl->r_brpl.rmp_session = 0;
24217186Sdfr	rpl->r_brpl.rmp_version = htons(RMP_VERSION);
24317186Sdfr
2441541Srgrimes	size = &rpl->r_brpl.rmp_flnmsize;	/* ptr to length of filename */
2451549Srgrimes	*size = 0;				/* init length to zero */
24683651Speter
2471541Srgrimes	/*
24883651Speter	 *  Copy the file name into the reply packet incrementing the
24983651Speter	 *  length as we go.  Stop at end of string or when RMPBOOTDATA
25083651Speter	 *  characters have been copied.  Also, set return code to
2511541Srgrimes	 *  indicate success or "no more files".
2521541Srgrimes	 */
2531541Srgrimes	if (i < C_MAXFILE && filelist[i] != NULL) {
25436519Speter		src = filelist[i];
25517186Sdfr		dst = (char *)&rpl->r_brpl.rmp_flnm;
25617186Sdfr		for (; *src && *size < RMPBOOTDATA; (*size)++) {
25736519Speter			if (*src == '\0')
25817186Sdfr				break;
2591541Srgrimes			*dst++ = *src++;
2601541Srgrimes		}
2611541Srgrimes		rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
2621541Srgrimes	} else
2631541Srgrimes		rpl->r_brpl.rmp_retcode = RMP_E_NODFLT;
2641541Srgrimes
2651541Srgrimes	rconn->rmplen = RMPBOOTSIZE(*size);	/* set packet length */
2661541Srgrimes
2671541Srgrimes	return(SendPacket(rconn));		/* send packet */
2681541Srgrimes}
2691541Srgrimes
2701541Srgrimes/*
2711541Srgrimes**  SendBootRepl -- open boot file and respond to boot request.
2721541Srgrimes**
2731541Srgrimes**	Parameters:
27470254Sbmilekic**		req - RMP BOOT packet containing the request.
2751541Srgrimes**		rconn - the reply packet to be formatted.
27670254Sbmilekic**		filelist - list of files available to the requester.
2771541Srgrimes**
2781541Srgrimes**	Returns:
2791541Srgrimes**		1 on success, 0 on failure.
2801541Srgrimes**
2811541Srgrimes**	Side Effects:
2821541Srgrimes**		none.
2831541Srgrimes*/
2841541Srgrimesint
2851541SrgrimesSendBootRepl(struct rmp_packet *req, RMPCONN *rconn, char *filelist[])
2861541Srgrimes{
2871541Srgrimes	int retval;
2881541Srgrimes	char *filename, filepath[RMPBOOTDATA+1];
2891541Srgrimes	RMPCONN *oldconn;
2901541Srgrimes	struct rmp_packet *rpl;
2911541Srgrimes	char *src, *dst1, *dst2;
2921541Srgrimes	u_int8_t i;
2931541Srgrimes
2941541Srgrimes	/*
2951541Srgrimes	 *  If another connection already exists, delete it since we
2961541Srgrimes	 *  are obviously starting again.
2971541Srgrimes	 */
2981541Srgrimes	if ((oldconn = FindConn(rconn)) != NULL) {
2991541Srgrimes		syslog(LOG_WARNING, "%s: dropping existing connection",
30017186Sdfr		       EnetStr(oldconn));
30117186Sdfr		RemoveConn(oldconn);
3021541Srgrimes	}
3031541Srgrimes
3041541Srgrimes	rpl = &rconn->rmp;			/* cache ptr to RMP packet */
3051541Srgrimes
30670254Sbmilekic	/*
3071541Srgrimes	 *  Set up assorted fields in reply packet.
3081541Srgrimes	 */
3091541Srgrimes	rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
3101541Srgrimes	COPYWORD(req->r_brq.rmp_seqno, rpl->r_brpl.rmp_seqno);
3111541Srgrimes	rpl->r_brpl.rmp_session = htons(GenSessID());
3121541Srgrimes	rpl->r_brpl.rmp_version = htons(RMP_VERSION);
3131541Srgrimes	rpl->r_brpl.rmp_flnmsize = req->r_brq.rmp_flnmsize;
3141541Srgrimes
3151541Srgrimes	/*
3161541Srgrimes	 *  Copy file name to `filepath' string, and into reply packet.
3171541Srgrimes	 */
3181541Srgrimes	src = &req->r_brq.rmp_flnm;
3191541Srgrimes	dst1 = filepath;
3201541Srgrimes	dst2 = &rpl->r_brpl.rmp_flnm;
3211541Srgrimes	for (i = 0; i < req->r_brq.rmp_flnmsize; i++)
3221541Srgrimes		*dst1++ = *dst2++ = *src++;
3231541Srgrimes	*dst1 = '\0';
3241549Srgrimes
32583651Speter	/*
3261541Srgrimes	 *  If we are booting HP-UX machines, their secondary loader will
32783651Speter	 *  ask for files like "/hp-ux".  As a security measure, we do not
3281541Srgrimes	 *  allow boot files to lay outside the boot directory (unless they
32936541Speter	 *  are purposely link'd out.  So, make `filename' become the path-
3301541Srgrimes	 *  stripped file name and spoof the client into thinking that it
3311541Srgrimes	 *  really got what it wanted.
3321541Srgrimes	 */
3331541Srgrimes	filename = (filename = strrchr(filepath,'/'))? ++filename: filepath;
3341541Srgrimes
3351541Srgrimes	/*
33636541Speter	 *  Check that this is a valid boot file name.
3371541Srgrimes	 */
3381541Srgrimes	for (i = 0; i < C_MAXFILE && filelist[i] != NULL; i++)
3391541Srgrimes		if (STREQN(filename, filelist[i]))
3401541Srgrimes			goto match;
3411541Srgrimes
3421541Srgrimes	/*
3431541Srgrimes	 *  Invalid boot file name, set error and send reply packet.
3441541Srgrimes	 */
3451541Srgrimes	rpl->r_brpl.rmp_retcode = RMP_E_NOFILE;
3461541Srgrimes	retval = 0;
3471541Srgrimes	goto sendpkt;
3481541Srgrimes
3491541Srgrimesmatch:
3501541Srgrimes	/*
35170254Sbmilekic	 *  This is a valid boot file.  Open the file and save the file
3521541Srgrimes	 *  descriptor associated with this connection and set success
35370254Sbmilekic	 *  indication.  If the file couldnt be opened, set error:
3541541Srgrimes	 *  	"no such file or dir" - RMP_E_NOFILE
3551541Srgrimes	 *	"file table overflow" - RMP_E_BUSY
3561541Srgrimes	 *	"too many open files" - RMP_E_BUSY
35736541Speter	 *	anything else         - RMP_E_OPENFILE
3581541Srgrimes	 */
3591541Srgrimes	if ((rconn->bootfd = open(filename, O_RDONLY, 0600)) < 0) {
3601541Srgrimes		rpl->r_brpl.rmp_retcode = (errno == ENOENT)? RMP_E_NOFILE:
3611541Srgrimes			(errno == EMFILE || errno == ENFILE)? RMP_E_BUSY:
3621541Srgrimes			RMP_E_OPENFILE;
3631541Srgrimes		retval = 0;
3641541Srgrimes	} else {
3651541Srgrimes		rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
3661541Srgrimes		retval = 1;
3671541Srgrimes	}
3681541Srgrimes
3691541Srgrimessendpkt:
3701541Srgrimes	syslog(LOG_INFO, "%s: request to boot %s (%s)",
3711541Srgrimes	       EnetStr(rconn), filename, retval? "granted": "denied");
3721541Srgrimes
3731541Srgrimes	rconn->rmplen = RMPBOOTSIZE(rpl->r_brpl.rmp_flnmsize);
3741541Srgrimes
3751541Srgrimes	return (retval & SendPacket(rconn));
3761541Srgrimes}
3771541Srgrimes
3781541Srgrimes/*
3791541Srgrimes**  SendReadRepl -- send a portion of the boot file to the requester.
3801541Srgrimes**
3811541Srgrimes**	Parameters:
3821541Srgrimes**		rconn - the reply packet to be formatted.
3831541Srgrimes**
3841541Srgrimes**	Returns:
3851541Srgrimes**		1 on success, 0 on failure.
3861549Srgrimes**
38783651Speter**	Side Effects:
3881541Srgrimes**		none.
38983651Speter*/
3901541Srgrimesint
39192783SjeffSendReadRepl(RMPCONN *rconn)
39292783Sjeff{
3931541Srgrimes	int retval = 0;
3941541Srgrimes	RMPCONN *oldconn;
3951541Srgrimes	struct rmp_packet *rpl, *req;
3961541Srgrimes	int size = 0;
3971541Srgrimes	int madeconn = 0;
3981541Srgrimes
3991541Srgrimes	/*
4001541Srgrimes	 *  Find the old connection.  If one doesn't exist, create one only
4011541Srgrimes	 *  to return the error code.
4021541Srgrimes	 */
4033664Sphk	if ((oldconn = FindConn(rconn)) == NULL) {
4049336Sdfr		if ((oldconn = NewConn(rconn)) == NULL)
4059336Sdfr			return(0);
4069336Sdfr		syslog(LOG_ERR, "SendReadRepl: no active connection (%s)",
4071541Srgrimes		       EnetStr(rconn));
40819449Sdfr		madeconn++;
4091541Srgrimes	}
41019449Sdfr
41119449Sdfr	req = &rconn->rmp;		/* cache ptr to request packet */
4121541Srgrimes	rpl = &oldconn->rmp;		/* cache ptr to reply packet */
4131541Srgrimes
4141541Srgrimes	if (madeconn) {			/* no active connection above; abort */
4151541Srgrimes		rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
4161541Srgrimes		retval = 1;
4173664Sphk		goto sendpkt;
41816365Sphk	}
4193305Sphk
4201549Srgrimes	/*
42183651Speter	 *  Make sure Session ID's match.
42283651Speter	 */
42383651Speter	if (ntohs(req->r_rrq.rmp_session) !=
42483651Speter	    ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session):
4252997Swollman	                                     ntohs(rpl->r_rrpl.rmp_session))) {
42642957Sdillon		syslog(LOG_ERR, "SendReadRepl: bad session id (%s)",
42742957Sdillon		       EnetStr(rconn));
4281549Srgrimes		rpl->r_rrpl.rmp_retcode = RMP_E_BADSID;
4291541Srgrimes		retval = 1;
4301541Srgrimes		goto sendpkt;
43138894Sbde	}
43283651Speter
43338894Sbde	/*
43438894Sbde	 *  If the requester asks for more data than we can fit,
43538894Sbde	 *  silently clamp the request size down to RMPREADDATA.
43683651Speter	 *
43783651Speter	 *  N.B. I do not know if this is "legal", however it seems
43838894Sbde	 *  to work.  This is necessary for bpfwrite() on machines
43938894Sbde	 *  with MCLBYTES less than 1514.
44038894Sbde	 */
4411541Srgrimes	if (ntohs(req->r_rrq.rmp_size) > RMPREADDATA)
4421541Srgrimes		req->r_rrq.rmp_size = htons(RMPREADDATA);
4431541Srgrimes
4441541Srgrimes	/*
4451541Srgrimes	 *  Position read head on file according to info in request packet.
4461541Srgrimes	 */
4471541Srgrimes	GETWORD(req->r_rrq.rmp_offset, size);
4481541Srgrimes	if (lseek(oldconn->bootfd, (off_t)size, SEEK_SET) < 0) {
4491541Srgrimes		syslog(LOG_ERR, "SendReadRepl: lseek: %m (%s)",
4501541Srgrimes		       EnetStr(rconn));
4511541Srgrimes		rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
4521541Srgrimes		retval = 1;
4531541Srgrimes		goto sendpkt;
4541541Srgrimes	}
4551549Srgrimes
45683651Speter	/*
45783651Speter	 *  Read data directly into reply packet.
4581541Srgrimes	 */
45983651Speter	if ((size = read(oldconn->bootfd, &rpl->r_rrpl.rmp_data,
46083651Speter	                 (int) ntohs(req->r_rrq.rmp_size))) <= 0) {
46183651Speter		if (size < 0) {
46283651Speter			syslog(LOG_ERR, "SendReadRepl: read: %m (%s)",
46383651Speter			       EnetStr(rconn));
4649336Sdfr			rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
46584057Speter		} else {
4661541Srgrimes			rpl->r_rrpl.rmp_retcode = RMP_E_EOF;
4671541Srgrimes		}
4681541Srgrimes		retval = 1;
4691541Srgrimes		goto sendpkt;
4709336Sdfr	}
4711541Srgrimes
4721541Srgrimes	/*
4739336Sdfr	 *  Set success indication.
47484057Speter	 */
47584057Speter	rpl->r_rrpl.rmp_retcode = RMP_E_OKAY;
47684057Speter
4779336Sdfrsendpkt:
4789336Sdfr	/*
4799336Sdfr	 *  Set up assorted fields in reply packet.
4809336Sdfr	 */
48148859Sphk	rpl->r_rrpl.rmp_type = RMP_READ_REPL;
48216634Sbde	COPYWORD(req->r_rrq.rmp_offset, rpl->r_rrpl.rmp_offset);
4839336Sdfr	rpl->r_rrpl.rmp_session = req->r_rrq.rmp_session;
4841541Srgrimes
4859336Sdfr	oldconn->rmplen = RMPREADSIZE(size);	/* set size of packet */
4869336Sdfr
4879336Sdfr	retval &= SendPacket(oldconn);		/* send packet */
4889336Sdfr
4899336Sdfr	if (madeconn)				/* clean up after ourself */
4909336Sdfr		FreeConn(oldconn);
4919336Sdfr
4929336Sdfr	return (retval);
4939336Sdfr}
4949336Sdfr
4959336Sdfr/*
4969336Sdfr**  BootDone -- free up memory allocated for a connection.
4979336Sdfr**
4989336Sdfr**	Parameters:
4999336Sdfr**		rconn - incoming boot complete packet.
5009336Sdfr**
5019336Sdfr**	Returns:
5029336Sdfr**		1 on success, 0 on failure.
5039336Sdfr**
5049336Sdfr**	Side Effects:
5059336Sdfr**		none.
5069336Sdfr*/
5079336Sdfrint
50836541SpeterBootDone(RMPCONN *rconn)
5099336Sdfr{
5109336Sdfr	RMPCONN *oldconn;
5119336Sdfr	struct rmp_packet *rpl;
5129336Sdfr
5139336Sdfr	/*
5149336Sdfr	 *  If we can't find the connection, ignore the request.
5159336Sdfr	 */
5161541Srgrimes	if ((oldconn = FindConn(rconn)) == NULL) {
5179336Sdfr		syslog(LOG_ERR, "BootDone: no existing connection (%s)",
5181541Srgrimes		       EnetStr(rconn));
5191541Srgrimes		return(0);
5208876Srgrimes	}
5211541Srgrimes
5221541Srgrimes	rpl = &oldconn->rmp;			/* cache ptr to RMP packet */
5231541Srgrimes
5241541Srgrimes	/*
5251541Srgrimes	 *  Make sure Session ID's match.
52610219Sdfr	 */
5279336Sdfr	if (ntohs(rconn->rmp.r_rrq.rmp_session) !=
5281541Srgrimes	    ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session):
5291541Srgrimes	                                    ntohs(rpl->r_rrpl.rmp_session))) {
5301541Srgrimes		syslog(LOG_ERR, "BootDone: bad session id (%s)",
5311541Srgrimes		       EnetStr(rconn));
5321541Srgrimes		return(0);
53363788Smckusick	}
53463788Smckusick
5351541Srgrimes	RemoveConn(oldconn);			/* remove connection */
53618397Snate
5371541Srgrimes	syslog(LOG_INFO, "%s: boot complete", EnetStr(rconn));
5381541Srgrimes
5391541Srgrimes	return(1);
5401541Srgrimes}
54147028Sphk
5421541Srgrimes/*
5431541Srgrimes**  SendPacket -- send an RMP packet to a remote host.
5449336Sdfr**
5459336Sdfr**	Parameters:
5469336Sdfr**		rconn - packet to be sent.
5479336Sdfr**
54847751Speter**	Returns:
5499336Sdfr**		1 on success, 0 on failure.
55047751Speter**
55136541Speter**	Side Effects:
55236541Speter**		none.
5539336Sdfr*/
5549336Sdfrint
5559336SdfrSendPacket(RMPCONN *rconn)
5569336Sdfr{
5571541Srgrimes	/*
5589336Sdfr	 *  Set Ethernet Destination address to Source (BPF and the enet
5599336Sdfr	 *  driver will take care of getting our source address set).
5609336Sdfr	 */
56136541Speter	memmove((char *)&rconn->rmp.hp_hdr.daddr[0],
56236541Speter	        (char *)&rconn->rmp.hp_hdr.saddr[0], RMP_ADDRLEN);
56347751Speter	rconn->rmp.hp_hdr.len = htons(rconn->rmplen - sizeof(struct hp_hdr));
56436541Speter
56536541Speter	/*
5669336Sdfr	 *  Reverse 802.2/HP Extended Source & Destination Access Pts.
5671541Srgrimes	 */
56836541Speter	rconn->rmp.hp_llc.dxsap = htons(HPEXT_SXSAP);
56936541Speter	rconn->rmp.hp_llc.sxsap = htons(HPEXT_DXSAP);
57018397Snate
57183651Speter	/*
5721541Srgrimes	 *  Last time this connection was active.
5731541Srgrimes	 */
57467486Sdwmalone	(void)gettimeofday(&rconn->tstamp, NULL);
5751541Srgrimes
5761541Srgrimes	if (DbgFp != NULL)			/* display packet */
57767486Sdwmalone		DispPkt(rconn,DIR_SENT);
57867486Sdwmalone
57967486Sdwmalone	/*
58067486Sdwmalone	 *  Send RMP packet to remote host.
58167486Sdwmalone	 */
58267486Sdwmalone	return(BpfWrite(rconn));
58367486Sdwmalone}
58467486Sdwmalone