Home | History | Annotate | Line # | Download | only in rbootd
rmpproto.c revision 1.14.44.1
      1  1.14.44.1   bouyer /*	$NetBSD: rmpproto.c,v 1.14.44.1 2011/02/17 12:00:59 bouyer Exp $	*/
      2       1.13      agc 
      3       1.13      agc /*
      4  1.14.44.1   bouyer  * Copyright (c) 1988, 1992 The University of Utah and the Center
      5  1.14.44.1   bouyer  *	for Software Science (CSS).
      6       1.13      agc  * Copyright (c) 1992, 1993
      7       1.13      agc  *	The Regents of the University of California.  All rights reserved.
      8       1.13      agc  *
      9       1.13      agc  * This code is derived from software contributed to Berkeley by
     10       1.13      agc  * the Center for Software Science of the University of Utah Computer
     11       1.13      agc  * Science Department.  CSS requests users of this software to return
     12       1.13      agc  * to css-dist (at) cs.utah.edu any improvements that they make and grant
     13       1.13      agc  * CSS redistribution rights.
     14       1.13      agc  *
     15       1.13      agc  * Redistribution and use in source and binary forms, with or without
     16       1.13      agc  * modification, are permitted provided that the following conditions
     17       1.13      agc  * are met:
     18       1.13      agc  * 1. Redistributions of source code must retain the above copyright
     19       1.13      agc  *    notice, this list of conditions and the following disclaimer.
     20       1.13      agc  * 2. Redistributions in binary form must reproduce the above copyright
     21       1.13      agc  *    notice, this list of conditions and the following disclaimer in the
     22       1.13      agc  *    documentation and/or other materials provided with the distribution.
     23       1.13      agc  * 3. Neither the name of the University nor the names of its contributors
     24       1.13      agc  *    may be used to endorse or promote products derived from this software
     25       1.13      agc  *    without specific prior written permission.
     26       1.13      agc  *
     27       1.13      agc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     28       1.13      agc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     29       1.13      agc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     30       1.13      agc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     31       1.13      agc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     32       1.13      agc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     33       1.13      agc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     34       1.13      agc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     35       1.13      agc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     36       1.13      agc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     37       1.13      agc  * SUCH DAMAGE.
     38       1.13      agc  *
     39       1.13      agc  *	from: @(#)rmpproto.c	8.1 (Berkeley) 6/4/93
     40       1.13      agc  *
     41       1.13      agc  * From: Utah Hdr: rmpproto.c 3.1 92/07/06
     42       1.13      agc  * Author: Jeff Forys, University of Utah CSS
     43       1.13      agc  */
     44        1.3  thorpej 
     45        1.8  thorpej #include <sys/cdefs.h>
     46        1.1   brezak #ifndef lint
     47        1.8  thorpej #if 0
     48        1.8  thorpej static char sccsid[] = "@(#)rmpproto.c	8.1 (Berkeley) 6/4/93";
     49        1.8  thorpej #else
     50  1.14.44.1   bouyer __RCSID("$NetBSD: rmpproto.c,v 1.14.44.1 2011/02/17 12:00:59 bouyer Exp $");
     51        1.8  thorpej #endif
     52        1.1   brezak #endif /* not lint */
     53        1.1   brezak 
     54        1.1   brezak #include <sys/param.h>
     55        1.1   brezak #include <sys/time.h>
     56        1.1   brezak 
     57        1.1   brezak #include <errno.h>
     58        1.1   brezak #include <fcntl.h>
     59        1.1   brezak #include <stdio.h>
     60        1.1   brezak #include <string.h>
     61        1.1   brezak #include <syslog.h>
     62        1.1   brezak #include <unistd.h>
     63        1.1   brezak #include "defs.h"
     64        1.1   brezak 
     65        1.1   brezak /*
     66        1.1   brezak **  ProcessPacket -- determine packet type and do what's required.
     67        1.1   brezak **
     68        1.1   brezak **	An RMP BOOT packet has been received.  Look at the type field
     69        1.1   brezak **	and process Boot Requests, Read Requests, and Boot Complete
     70        1.1   brezak **	packets.  Any other type will be dropped with a warning msg.
     71        1.1   brezak **
     72        1.1   brezak **	Parameters:
     73        1.1   brezak **		rconn - the new connection
     74        1.1   brezak **		client - list of files available to this host
     75        1.1   brezak **
     76        1.1   brezak **	Returns:
     77        1.1   brezak **		Nothing.
     78        1.1   brezak **
     79        1.1   brezak **	Side Effects:
     80        1.1   brezak **		- If this is a valid boot request, it will be added to
     81        1.1   brezak **		  the linked list of outstanding requests (RmpConns).
     82        1.1   brezak **		- If this is a valid boot complete, its associated
     83        1.1   brezak **		  entry in RmpConns will be deleted.
     84        1.1   brezak **		- Also, unless we run out of memory, a reply will be
     85        1.1   brezak **		  sent to the host that sent the packet.
     86        1.1   brezak */
     87        1.1   brezak void
     88        1.1   brezak ProcessPacket(rconn, client)
     89        1.1   brezak 	RMPCONN *rconn;
     90        1.1   brezak 	CLIENT *client;
     91        1.1   brezak {
     92        1.1   brezak 	struct rmp_packet *rmp;
     93        1.1   brezak 	RMPCONN *rconnout;
     94        1.1   brezak 
     95        1.1   brezak 	rmp = &rconn->rmp;		/* cache pointer to RMP packet */
     96        1.1   brezak 
     97        1.1   brezak 	switch(rmp->r_type) {		/* do what we came here to do */
     98        1.1   brezak 		case RMP_BOOT_REQ:		/* boot request */
     99        1.1   brezak 			if ((rconnout = NewConn(rconn)) == NULL)
    100        1.1   brezak 				return;
    101        1.1   brezak 
    102        1.1   brezak 			/*
    103        1.1   brezak 			 *  If the Session ID is 0xffff, this is a "probe"
    104        1.1   brezak 			 *  packet and we do not want to add the connection
    105        1.1   brezak 			 *  to the linked list of active connections.  There
    106        1.1   brezak 			 *  are two types of probe packets, if the Sequence
    107        1.1   brezak 			 *  Number is 0 they want to know our host name, o/w
    108        1.1   brezak 			 *  they want the name of the file associated with
    109        1.1   brezak 			 *  the number spec'd by the Sequence Number.
    110        1.1   brezak 			 *
    111        1.1   brezak 			 *  If this is an actual boot request, open the file
    112        1.1   brezak 			 *  and send a reply.  If SendBootRepl() does not
    113        1.1   brezak 			 *  return 0, add the connection to the linked list
    114        1.1   brezak 			 *  of active connections, otherwise delete it since
    115        1.1   brezak 			 *  an error was encountered.
    116        1.1   brezak 			 */
    117        1.2   brezak 			if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) {
    118        1.1   brezak 				if (WORDZE(rmp->r_brq.rmp_seqno))
    119        1.1   brezak 					(void) SendServerID(rconnout);
    120        1.1   brezak 				else
    121        1.1   brezak 					(void) SendFileNo(rmp, rconnout,
    122        1.1   brezak 					                  client? client->files:
    123        1.1   brezak 					                          BootFiles);
    124        1.1   brezak 				FreeConn(rconnout);
    125        1.1   brezak 			} else {
    126        1.1   brezak 				if (SendBootRepl(rmp, rconnout,
    127        1.1   brezak 				    client? client->files: BootFiles))
    128        1.1   brezak 					AddConn(rconnout);
    129        1.1   brezak 				else
    130        1.1   brezak 					FreeConn(rconnout);
    131        1.1   brezak 			}
    132        1.1   brezak 			break;
    133        1.1   brezak 
    134        1.1   brezak 		case RMP_BOOT_REPL:		/* boot reply (not valid) */
    135        1.1   brezak 			syslog(LOG_WARNING, "%s: sent a boot reply",
    136        1.1   brezak 			       EnetStr(rconn));
    137        1.1   brezak 			break;
    138        1.1   brezak 
    139        1.1   brezak 		case RMP_READ_REQ:		/* read request */
    140        1.1   brezak 			/*
    141        1.1   brezak 			 *  Send a portion of the boot file.
    142        1.1   brezak 			 */
    143        1.1   brezak 			(void) SendReadRepl(rconn);
    144        1.1   brezak 			break;
    145        1.1   brezak 
    146        1.1   brezak 		case RMP_READ_REPL:		/* read reply (not valid) */
    147        1.1   brezak 			syslog(LOG_WARNING, "%s: sent a read reply",
    148        1.1   brezak 			       EnetStr(rconn));
    149        1.1   brezak 			break;
    150        1.1   brezak 
    151        1.1   brezak 		case RMP_BOOT_DONE:		/* boot complete */
    152        1.1   brezak 			/*
    153        1.1   brezak 			 *  Remove the entry from the linked list of active
    154        1.1   brezak 			 *  connections.
    155        1.1   brezak 			 */
    156        1.1   brezak 			(void) BootDone(rconn);
    157        1.1   brezak 			break;
    158        1.1   brezak 
    159        1.1   brezak 		default:			/* unknown RMP packet type */
    160        1.1   brezak 			syslog(LOG_WARNING, "%s: unknown packet type (%u)",
    161        1.1   brezak 			       EnetStr(rconn), rmp->r_type);
    162        1.1   brezak 	}
    163        1.1   brezak }
    164        1.1   brezak 
    165        1.1   brezak /*
    166        1.1   brezak **  SendServerID -- send our host name to who ever requested it.
    167        1.1   brezak **
    168        1.1   brezak **	Parameters:
    169        1.1   brezak **		rconn - the reply packet to be formatted.
    170        1.1   brezak **
    171        1.1   brezak **	Returns:
    172        1.1   brezak **		1 on success, 0 on failure.
    173        1.1   brezak **
    174        1.1   brezak **	Side Effects:
    175        1.1   brezak **		none.
    176        1.1   brezak */
    177        1.1   brezak int
    178        1.1   brezak SendServerID(rconn)
    179        1.1   brezak 	RMPCONN *rconn;
    180        1.1   brezak {
    181       1.10    lukem 	struct rmp_packet *rpl;
    182       1.10    lukem 	char *src, *dst;
    183       1.10    lukem 	u_int8_t *size;
    184        1.1   brezak 
    185        1.1   brezak 	rpl = &rconn->rmp;			/* cache ptr to RMP packet */
    186        1.1   brezak 
    187        1.1   brezak 	/*
    188        1.1   brezak 	 *  Set up assorted fields in reply packet.
    189        1.1   brezak 	 */
    190        1.1   brezak 	rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
    191        1.1   brezak 	rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
    192        1.1   brezak 	ZEROWORD(rpl->r_brpl.rmp_seqno);
    193        1.1   brezak 	rpl->r_brpl.rmp_session = 0;
    194        1.2   brezak 	rpl->r_brpl.rmp_version = htons(RMP_VERSION);
    195        1.1   brezak 
    196        1.1   brezak 	size = &rpl->r_brpl.rmp_flnmsize;	/* ptr to length of host name */
    197        1.1   brezak 
    198        1.1   brezak 	/*
    199        1.1   brezak 	 *  Copy our host name into the reply packet incrementing the
    200        1.1   brezak 	 *  length as we go.  Stop at RMP_HOSTLEN or the first dot.
    201        1.1   brezak 	 */
    202        1.1   brezak 	src = MyHost;
    203        1.1   brezak 	dst = (char *) &rpl->r_brpl.rmp_flnm;
    204        1.1   brezak 	for (*size = 0; *size < RMP_HOSTLEN; (*size)++) {
    205        1.1   brezak 		if (*src == '.' || *src == '\0')
    206        1.1   brezak 			break;
    207        1.1   brezak 		*dst++ = *src++;
    208        1.1   brezak 	}
    209        1.1   brezak 
    210        1.1   brezak 	rconn->rmplen = RMPBOOTSIZE(*size);	/* set packet length */
    211        1.1   brezak 
    212        1.1   brezak 	return(SendPacket(rconn));		/* send packet */
    213        1.1   brezak }
    214        1.1   brezak 
    215        1.1   brezak /*
    216        1.1   brezak **  SendFileNo -- send the name of a bootable file to the requester.
    217        1.1   brezak **
    218        1.1   brezak **	Parameters:
    219        1.1   brezak **		req - RMP BOOT packet containing the request.
    220        1.1   brezak **		rconn - the reply packet to be formatted.
    221        1.1   brezak **		filelist - list of files available to the requester.
    222        1.1   brezak **
    223        1.1   brezak **	Returns:
    224        1.1   brezak **		1 on success, 0 on failure.
    225        1.1   brezak **
    226        1.1   brezak **	Side Effects:
    227        1.1   brezak **		none.
    228        1.1   brezak */
    229        1.1   brezak int
    230        1.1   brezak SendFileNo(req, rconn, filelist)
    231        1.1   brezak 	struct rmp_packet *req;
    232        1.1   brezak 	RMPCONN *rconn;
    233        1.1   brezak 	char *filelist[];
    234        1.1   brezak {
    235       1.10    lukem 	struct rmp_packet *rpl;
    236       1.10    lukem 	char *src, *dst;
    237       1.10    lukem 	u_int8_t *size;
    238       1.10    lukem 	int i;
    239        1.1   brezak 
    240        1.1   brezak 	GETWORD(req->r_brpl.rmp_seqno, i);	/* SeqNo is really FileNo */
    241        1.1   brezak 	rpl = &rconn->rmp;			/* cache ptr to RMP packet */
    242        1.1   brezak 
    243        1.1   brezak 	/*
    244        1.1   brezak 	 *  Set up assorted fields in reply packet.
    245        1.1   brezak 	 */
    246        1.1   brezak 	rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
    247        1.1   brezak 	PUTWORD(i, rpl->r_brpl.rmp_seqno);
    248        1.1   brezak 	i--;
    249        1.1   brezak 	rpl->r_brpl.rmp_session = 0;
    250        1.2   brezak 	rpl->r_brpl.rmp_version = htons(RMP_VERSION);
    251        1.1   brezak 
    252        1.1   brezak 	size = &rpl->r_brpl.rmp_flnmsize;	/* ptr to length of filename */
    253        1.1   brezak 	*size = 0;				/* init length to zero */
    254        1.1   brezak 
    255        1.1   brezak 	/*
    256        1.1   brezak 	 *  Copy the file name into the reply packet incrementing the
    257        1.1   brezak 	 *  length as we go.  Stop at end of string or when RMPBOOTDATA
    258        1.1   brezak 	 *  characters have been copied.  Also, set return code to
    259        1.1   brezak 	 *  indicate success or "no more files".
    260        1.1   brezak 	 */
    261        1.1   brezak 	if (i < C_MAXFILE && filelist[i] != NULL) {
    262        1.1   brezak 		src = filelist[i];
    263        1.1   brezak 		dst = (char *)&rpl->r_brpl.rmp_flnm;
    264        1.1   brezak 		for (; *src && *size < RMPBOOTDATA; (*size)++) {
    265        1.1   brezak 			if (*src == '\0')
    266        1.1   brezak 				break;
    267        1.1   brezak 			*dst++ = *src++;
    268        1.1   brezak 		}
    269        1.1   brezak 		rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
    270        1.1   brezak 	} else
    271        1.1   brezak 		rpl->r_brpl.rmp_retcode = RMP_E_NODFLT;
    272        1.1   brezak 
    273        1.1   brezak 	rconn->rmplen = RMPBOOTSIZE(*size);	/* set packet length */
    274        1.1   brezak 
    275        1.1   brezak 	return(SendPacket(rconn));		/* send packet */
    276        1.1   brezak }
    277        1.1   brezak 
    278        1.1   brezak /*
    279        1.1   brezak **  SendBootRepl -- open boot file and respond to boot request.
    280        1.1   brezak **
    281        1.1   brezak **	Parameters:
    282        1.1   brezak **		req - RMP BOOT packet containing the request.
    283        1.1   brezak **		rconn - the reply packet to be formatted.
    284        1.1   brezak **		filelist - list of files available to the requester.
    285        1.1   brezak **
    286        1.1   brezak **	Returns:
    287        1.1   brezak **		1 on success, 0 on failure.
    288        1.1   brezak **
    289        1.1   brezak **	Side Effects:
    290        1.1   brezak **		none.
    291        1.1   brezak */
    292        1.1   brezak int
    293        1.1   brezak SendBootRepl(req, rconn, filelist)
    294        1.1   brezak 	struct rmp_packet *req;
    295        1.1   brezak 	RMPCONN *rconn;
    296        1.1   brezak 	char *filelist[];
    297        1.1   brezak {
    298        1.1   brezak 	int retval;
    299        1.1   brezak 	char *filename, filepath[RMPBOOTDATA+1];
    300        1.1   brezak 	RMPCONN *oldconn;
    301       1.10    lukem 	struct rmp_packet *rpl;
    302       1.10    lukem 	char *src, *dst1, *dst2;
    303       1.10    lukem 	u_int8_t i;
    304        1.1   brezak 
    305        1.1   brezak 	/*
    306        1.1   brezak 	 *  If another connection already exists, delete it since we
    307        1.1   brezak 	 *  are obviously starting again.
    308        1.1   brezak 	 */
    309        1.1   brezak 	if ((oldconn = FindConn(rconn)) != NULL) {
    310        1.1   brezak 		syslog(LOG_WARNING, "%s: dropping existing connection",
    311        1.1   brezak 		       EnetStr(oldconn));
    312        1.1   brezak 		RemoveConn(oldconn);
    313        1.1   brezak 	}
    314        1.1   brezak 
    315        1.1   brezak 	rpl = &rconn->rmp;			/* cache ptr to RMP packet */
    316        1.1   brezak 
    317        1.1   brezak 	/*
    318        1.1   brezak 	 *  Set up assorted fields in reply packet.
    319        1.1   brezak 	 */
    320        1.1   brezak 	rpl->r_brpl.rmp_type = RMP_BOOT_REPL;
    321        1.1   brezak 	COPYWORD(req->r_brq.rmp_seqno, rpl->r_brpl.rmp_seqno);
    322        1.2   brezak 	rpl->r_brpl.rmp_session = htons(GenSessID());
    323        1.2   brezak 	rpl->r_brpl.rmp_version = htons(RMP_VERSION);
    324        1.1   brezak 	rpl->r_brpl.rmp_flnmsize = req->r_brq.rmp_flnmsize;
    325        1.1   brezak 
    326        1.1   brezak 	/*
    327        1.1   brezak 	 *  Copy file name to `filepath' string, and into reply packet.
    328        1.1   brezak 	 */
    329        1.1   brezak 	dst1 = filepath;
    330        1.1   brezak 	dst2 = &rpl->r_brpl.rmp_flnm;
    331       1.11   bouyer 	if (req->r_brq.rmp_flnmsize)
    332       1.11   bouyer 		src = &req->r_brq.rmp_flnm;
    333       1.11   bouyer 	else {
    334       1.11   bouyer 		/* no file supplied, substitute the first one */
    335       1.11   bouyer 		src = filelist[0];
    336       1.11   bouyer 		req->r_brq.rmp_flnmsize = strlen(src);
    337       1.11   bouyer 	}
    338        1.1   brezak 	for (i = 0; i < req->r_brq.rmp_flnmsize; i++)
    339        1.1   brezak 		*dst1++ = *dst2++ = *src++;
    340        1.1   brezak 	*dst1 = '\0';
    341        1.1   brezak 
    342        1.1   brezak 	/*
    343        1.1   brezak 	 *  If we are booting HP-UX machines, their secondary loader will
    344        1.1   brezak 	 *  ask for files like "/hp-ux".  As a security measure, we do not
    345        1.1   brezak 	 *  allow boot files to lay outside the boot directory (unless they
    346        1.1   brezak 	 *  are purposely link'd out.  So, make `filename' become the path-
    347        1.1   brezak 	 *  stripped file name and spoof the client into thinking that it
    348        1.1   brezak 	 *  really got what it wanted.
    349        1.1   brezak 	 */
    350       1.12      cgd 	if ((filename = strrchr(filepath,'/')) != NULL)
    351       1.12      cgd 		filename++;
    352       1.12      cgd 	else
    353       1.12      cgd 		filename = filepath;
    354        1.1   brezak 
    355        1.1   brezak 	/*
    356        1.1   brezak 	 *  Check that this is a valid boot file name.
    357        1.1   brezak 	 */
    358        1.1   brezak 	for (i = 0; i < C_MAXFILE && filelist[i] != NULL; i++)
    359        1.1   brezak 		if (STREQN(filename, filelist[i]))
    360        1.1   brezak 			goto match;
    361        1.1   brezak 
    362        1.1   brezak 	/*
    363        1.1   brezak 	 *  Invalid boot file name, set error and send reply packet.
    364        1.1   brezak 	 */
    365        1.1   brezak 	rpl->r_brpl.rmp_retcode = RMP_E_NOFILE;
    366        1.1   brezak 	retval = 0;
    367        1.1   brezak 	goto sendpkt;
    368        1.1   brezak 
    369        1.1   brezak match:
    370        1.1   brezak 	/*
    371        1.1   brezak 	 *  This is a valid boot file.  Open the file and save the file
    372        1.1   brezak 	 *  descriptor associated with this connection and set success
    373        1.1   brezak 	 *  indication.  If the file couldnt be opened, set error:
    374        1.1   brezak 	 *  	"no such file or dir" - RMP_E_NOFILE
    375        1.1   brezak 	 *	"file table overflow" - RMP_E_BUSY
    376        1.1   brezak 	 *	"too many open files" - RMP_E_BUSY
    377        1.1   brezak 	 *	anything else         - RMP_E_OPENFILE
    378        1.1   brezak 	 */
    379        1.1   brezak 	if ((rconn->bootfd = open(filename, O_RDONLY, 0600)) < 0) {
    380        1.1   brezak 		rpl->r_brpl.rmp_retcode = (errno == ENOENT)? RMP_E_NOFILE:
    381        1.1   brezak 			(errno == EMFILE || errno == ENFILE)? RMP_E_BUSY:
    382        1.1   brezak 			RMP_E_OPENFILE;
    383        1.1   brezak 		retval = 0;
    384        1.1   brezak 	} else {
    385        1.1   brezak 		rpl->r_brpl.rmp_retcode = RMP_E_OKAY;
    386        1.1   brezak 		retval = 1;
    387        1.1   brezak 	}
    388        1.1   brezak 
    389        1.1   brezak sendpkt:
    390        1.1   brezak 	syslog(LOG_INFO, "%s: request to boot %s (%s)",
    391        1.1   brezak 	       EnetStr(rconn), filename, retval? "granted": "denied");
    392        1.1   brezak 
    393        1.1   brezak 	rconn->rmplen = RMPBOOTSIZE(rpl->r_brpl.rmp_flnmsize);
    394        1.1   brezak 
    395        1.1   brezak 	return (retval & SendPacket(rconn));
    396        1.1   brezak }
    397        1.1   brezak 
    398        1.1   brezak /*
    399        1.1   brezak **  SendReadRepl -- send a portion of the boot file to the requester.
    400        1.1   brezak **
    401        1.1   brezak **	Parameters:
    402        1.1   brezak **		rconn - the reply packet to be formatted.
    403        1.1   brezak **
    404        1.1   brezak **	Returns:
    405        1.1   brezak **		1 on success, 0 on failure.
    406        1.1   brezak **
    407        1.1   brezak **	Side Effects:
    408        1.1   brezak **		none.
    409        1.1   brezak */
    410        1.1   brezak int
    411        1.1   brezak SendReadRepl(rconn)
    412        1.1   brezak 	RMPCONN *rconn;
    413        1.1   brezak {
    414        1.5  thorpej 	int retval = 0;
    415        1.1   brezak 	RMPCONN *oldconn;
    416       1.10    lukem 	struct rmp_packet *rpl, *req;
    417       1.10    lukem 	int size = 0;
    418        1.1   brezak 	int madeconn = 0;
    419        1.1   brezak 
    420        1.1   brezak 	/*
    421        1.1   brezak 	 *  Find the old connection.  If one doesnt exist, create one only
    422        1.1   brezak 	 *  to return the error code.
    423        1.1   brezak 	 */
    424        1.1   brezak 	if ((oldconn = FindConn(rconn)) == NULL) {
    425        1.1   brezak 		if ((oldconn = NewConn(rconn)) == NULL)
    426        1.1   brezak 			return(0);
    427        1.1   brezak 		syslog(LOG_ERR, "SendReadRepl: no active connection (%s)",
    428        1.1   brezak 		       EnetStr(rconn));
    429        1.1   brezak 		madeconn++;
    430        1.1   brezak 	}
    431        1.1   brezak 
    432        1.1   brezak 	req = &rconn->rmp;		/* cache ptr to request packet */
    433        1.1   brezak 	rpl = &oldconn->rmp;		/* cache ptr to reply packet */
    434        1.1   brezak 
    435        1.1   brezak 	if (madeconn) {			/* no active connection above; abort */
    436        1.1   brezak 		rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
    437        1.1   brezak 		retval = 1;
    438        1.1   brezak 		goto sendpkt;
    439        1.1   brezak 	}
    440        1.1   brezak 
    441        1.1   brezak 	/*
    442        1.1   brezak 	 *  Make sure Session ID's match.
    443        1.1   brezak 	 */
    444        1.2   brezak 	if (ntohs(req->r_rrq.rmp_session) !=
    445        1.2   brezak 	    ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session):
    446        1.2   brezak 	                                     ntohs(rpl->r_rrpl.rmp_session))) {
    447        1.1   brezak 		syslog(LOG_ERR, "SendReadRepl: bad session id (%s)",
    448        1.1   brezak 		       EnetStr(rconn));
    449        1.1   brezak 		rpl->r_rrpl.rmp_retcode = RMP_E_BADSID;
    450        1.1   brezak 		retval = 1;
    451        1.1   brezak 		goto sendpkt;
    452        1.1   brezak 	}
    453        1.1   brezak 
    454        1.1   brezak 	/*
    455        1.1   brezak 	 *  If the requester asks for more data than we can fit,
    456        1.1   brezak 	 *  silently clamp the request size down to RMPREADDATA.
    457        1.1   brezak 	 *
    458        1.1   brezak 	 *  N.B. I do not know if this is "legal", however it seems
    459        1.1   brezak 	 *  to work.  This is necessary for bpfwrite() on machines
    460        1.1   brezak 	 *  with MCLBYTES less than 1514.
    461        1.1   brezak 	 */
    462        1.2   brezak 	if (ntohs(req->r_rrq.rmp_size) > RMPREADDATA)
    463        1.2   brezak 		req->r_rrq.rmp_size = htons(RMPREADDATA);
    464        1.1   brezak 
    465        1.1   brezak 	/*
    466        1.1   brezak 	 *  Position read head on file according to info in request packet.
    467        1.1   brezak 	 */
    468        1.1   brezak 	GETWORD(req->r_rrq.rmp_offset, size);
    469        1.9   kleink 	if (lseek(oldconn->bootfd, (off_t)size, SEEK_SET) < 0) {
    470        1.1   brezak 		syslog(LOG_ERR, "SendReadRepl: lseek: %m (%s)",
    471        1.1   brezak 		       EnetStr(rconn));
    472        1.1   brezak 		rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
    473        1.1   brezak 		retval = 1;
    474        1.1   brezak 		goto sendpkt;
    475        1.1   brezak 	}
    476        1.1   brezak 
    477        1.1   brezak 	/*
    478        1.1   brezak 	 *  Read data directly into reply packet.
    479        1.1   brezak 	 */
    480        1.1   brezak 	if ((size = read(oldconn->bootfd, &rpl->r_rrpl.rmp_data,
    481        1.4  thorpej 	                 (int) ntohs(req->r_rrq.rmp_size))) <= 0) {
    482        1.1   brezak 		if (size < 0) {
    483        1.1   brezak 			syslog(LOG_ERR, "SendReadRepl: read: %m (%s)",
    484        1.1   brezak 			       EnetStr(rconn));
    485        1.1   brezak 			rpl->r_rrpl.rmp_retcode = RMP_E_ABORT;
    486        1.1   brezak 		} else {
    487        1.1   brezak 			rpl->r_rrpl.rmp_retcode = RMP_E_EOF;
    488        1.1   brezak 		}
    489        1.1   brezak 		retval = 1;
    490        1.1   brezak 		goto sendpkt;
    491        1.1   brezak 	}
    492        1.1   brezak 
    493        1.1   brezak 	/*
    494        1.1   brezak 	 *  Set success indication.
    495        1.1   brezak 	 */
    496        1.1   brezak 	rpl->r_rrpl.rmp_retcode = RMP_E_OKAY;
    497        1.1   brezak 
    498        1.1   brezak sendpkt:
    499        1.1   brezak 	/*
    500        1.1   brezak 	 *  Set up assorted fields in reply packet.
    501        1.1   brezak 	 */
    502        1.1   brezak 	rpl->r_rrpl.rmp_type = RMP_READ_REPL;
    503        1.1   brezak 	COPYWORD(req->r_rrq.rmp_offset, rpl->r_rrpl.rmp_offset);
    504        1.1   brezak 	rpl->r_rrpl.rmp_session = req->r_rrq.rmp_session;
    505        1.1   brezak 
    506        1.1   brezak 	oldconn->rmplen = RMPREADSIZE(size);	/* set size of packet */
    507        1.1   brezak 
    508        1.1   brezak 	retval &= SendPacket(oldconn);		/* send packet */
    509        1.1   brezak 
    510        1.1   brezak 	if (madeconn)				/* clean up after ourself */
    511        1.1   brezak 		FreeConn(oldconn);
    512        1.1   brezak 
    513        1.1   brezak 	return (retval);
    514        1.1   brezak }
    515        1.1   brezak 
    516        1.1   brezak /*
    517        1.1   brezak **  BootDone -- free up memory allocated for a connection.
    518        1.1   brezak **
    519        1.1   brezak **	Parameters:
    520        1.1   brezak **		rconn - incoming boot complete packet.
    521        1.1   brezak **
    522        1.1   brezak **	Returns:
    523        1.1   brezak **		1 on success, 0 on failure.
    524        1.1   brezak **
    525        1.1   brezak **	Side Effects:
    526        1.1   brezak **		none.
    527        1.1   brezak */
    528        1.1   brezak int
    529        1.1   brezak BootDone(rconn)
    530        1.1   brezak 	RMPCONN *rconn;
    531        1.1   brezak {
    532        1.1   brezak 	RMPCONN *oldconn;
    533        1.1   brezak 	struct rmp_packet *rpl;
    534        1.1   brezak 
    535        1.1   brezak 	/*
    536        1.1   brezak 	 *  If we cant find the connection, ignore the request.
    537        1.1   brezak 	 */
    538        1.1   brezak 	if ((oldconn = FindConn(rconn)) == NULL) {
    539        1.1   brezak 		syslog(LOG_ERR, "BootDone: no existing connection (%s)",
    540        1.1   brezak 		       EnetStr(rconn));
    541        1.1   brezak 		return(0);
    542        1.1   brezak 	}
    543        1.1   brezak 
    544        1.1   brezak 	rpl = &oldconn->rmp;			/* cache ptr to RMP packet */
    545        1.1   brezak 
    546        1.1   brezak 	/*
    547        1.1   brezak 	 *  Make sure Session ID's match.
    548        1.1   brezak 	 */
    549        1.2   brezak 	if (ntohs(rconn->rmp.r_rrq.rmp_session) !=
    550        1.2   brezak 	    ((rpl->r_type == RMP_BOOT_REPL)? ntohs(rpl->r_brpl.rmp_session):
    551        1.2   brezak 	                                    ntohs(rpl->r_rrpl.rmp_session))) {
    552        1.1   brezak 		syslog(LOG_ERR, "BootDone: bad session id (%s)",
    553        1.1   brezak 		       EnetStr(rconn));
    554        1.1   brezak 		return(0);
    555        1.1   brezak 	}
    556        1.1   brezak 
    557        1.1   brezak 	RemoveConn(oldconn);			/* remove connection */
    558        1.1   brezak 
    559        1.1   brezak 	syslog(LOG_INFO, "%s: boot complete", EnetStr(rconn));
    560        1.1   brezak 
    561        1.1   brezak 	return(1);
    562        1.1   brezak }
    563        1.1   brezak 
    564        1.1   brezak /*
    565        1.1   brezak **  SendPacket -- send an RMP packet to a remote host.
    566        1.1   brezak **
    567        1.1   brezak **	Parameters:
    568        1.1   brezak **		rconn - packet to be sent.
    569        1.1   brezak **
    570        1.1   brezak **	Returns:
    571        1.1   brezak **		1 on success, 0 on failure.
    572        1.1   brezak **
    573        1.1   brezak **	Side Effects:
    574        1.1   brezak **		none.
    575        1.1   brezak */
    576        1.1   brezak int
    577        1.1   brezak SendPacket(rconn)
    578       1.10    lukem 	RMPCONN *rconn;
    579        1.1   brezak {
    580        1.1   brezak 	/*
    581        1.1   brezak 	 *  Set Ethernet Destination address to Source (BPF and the enet
    582        1.1   brezak 	 *  driver will take care of getting our source address set).
    583        1.1   brezak 	 */
    584       1.10    lukem 	memmove((char *)&rconn->rmp.hp_hdr.daddr[0],
    585       1.10    lukem 	    (char *)&rconn->rmp.hp_hdr.saddr[0], RMP_ADDRLEN);
    586        1.6  thorpej 	rconn->rmp.hp_hdr.len = htons(rconn->rmplen - sizeof(struct hp_hdr));
    587        1.1   brezak 
    588        1.1   brezak 	/*
    589        1.1   brezak 	 *  Reverse 802.2/HP Extended Source & Destination Access Pts.
    590        1.1   brezak 	 */
    591        1.4  thorpej 	rconn->rmp.hp_llc.dxsap = htons(HPEXT_SXSAP);
    592        1.4  thorpej 	rconn->rmp.hp_llc.sxsap = htons(HPEXT_DXSAP);
    593        1.1   brezak 
    594        1.1   brezak 	/*
    595        1.1   brezak 	 *  Last time this connection was active.
    596        1.1   brezak 	 */
    597        1.1   brezak 	(void) gettimeofday(&rconn->tstamp, (struct timezone *)0);
    598        1.1   brezak 
    599        1.1   brezak 	if (DbgFp != NULL)			/* display packet */
    600        1.1   brezak 		DispPkt(rconn,DIR_SENT);
    601        1.1   brezak 
    602        1.1   brezak 	/*
    603        1.1   brezak 	 *  Send RMP packet to remote host.
    604        1.1   brezak 	 */
    605        1.1   brezak 	return(BpfWrite(rconn));
    606        1.1   brezak }
    607