Home | History | Annotate | Line # | Download | only in rbootd
utils.c revision 1.1.1.1
      1 /*
      2  * Copyright (c) 1988, 1992 The University of Utah and the Center
      3  *	for Software Science (CSS).
      4  * Copyright (c) 1992, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * the Center for Software Science of the University of Utah Computer
      9  * Science Department.  CSS requests users of this software to return
     10  * to css-dist (at) cs.utah.edu any improvements that they make and grant
     11  * CSS redistribution rights.
     12  *
     13  * Redistribution and use in source and binary forms, with or without
     14  * modification, are permitted provided that the following conditions
     15  * are met:
     16  * 1. Redistributions of source code must retain the above copyright
     17  *    notice, this list of conditions and the following disclaimer.
     18  * 2. Redistributions in binary form must reproduce the above copyright
     19  *    notice, this list of conditions and the following disclaimer in the
     20  *    documentation and/or other materials provided with the distribution.
     21  * 3. All advertising materials mentioning features or use of this software
     22  *    must display the following acknowledgement:
     23  *	This product includes software developed by the University of
     24  *	California, Berkeley and its contributors.
     25  * 4. Neither the name of the University nor the names of its contributors
     26  *    may be used to endorse or promote products derived from this software
     27  *    without specific prior written permission.
     28  *
     29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     39  * SUCH DAMAGE.
     40  *
     41  *	@(#)utils.c	8.1 (Berkeley) 6/4/93
     42  *
     43  * Utah $Hdr: utils.c 3.1 92/07/06$
     44  * Author: Jeff Forys, University of Utah CSS
     45  */
     46 
     47 #ifndef lint
     48 static char sccsid[] = "@(#)utils.c	8.1 (Berkeley) 6/4/93";
     49 #endif /* not lint */
     50 
     51 #include <sys/param.h>
     52 
     53 #include <fcntl.h>
     54 #include <signal.h>
     55 #include <stdio.h>
     56 #include <stdlib.h>
     57 #include <string.h>
     58 #include <syslog.h>
     59 #include <time.h>
     60 #include <unistd.h>
     61 #include "defs.h"
     62 
     63 /*
     64 **  DispPkt -- Display the contents of an RMPCONN packet.
     65 **
     66 **	Parameters:
     67 **		rconn - packet to be displayed.
     68 **		direct - direction packet is going (DIR_*).
     69 **
     70 **	Returns:
     71 **		Nothing.
     72 **
     73 **	Side Effects:
     74 **		None.
     75 */
     76 void
     77 DispPkt(rconn, direct)
     78 	RMPCONN *rconn;
     79 	int direct;
     80 {
     81 	static char BootFmt[] = "\t\tRetCode:%u SeqNo:%lx SessID:%x Vers:%u";
     82 	static char ReadFmt[] = "\t\tRetCode:%u Offset:%lx SessID:%x\n";
     83 
     84 	struct tm *tmp;
     85 	register struct rmp_packet *rmp;
     86 	int i, omask;
     87 	u_int t;
     88 
     89 	/*
     90 	 *  Since we will be working with RmpConns as well as DbgFp, we
     91 	 *  must block signals that can affect either.
     92 	 */
     93 	omask = sigblock(sigmask(SIGHUP)|sigmask(SIGUSR1)|sigmask(SIGUSR2));
     94 
     95 	if (DbgFp == NULL) {			/* sanity */
     96 		(void) sigsetmask(omask);
     97 		return;
     98 	}
     99 
    100 	/* display direction packet is going using '>>>' or '<<<' */
    101 	fputs((direct==DIR_RCVD)?"<<< ":(direct==DIR_SENT)?">>> ":"", DbgFp);
    102 
    103 	/* display packet timestamp */
    104 	tmp = localtime((time_t *)&rconn->tstamp.tv_sec);
    105 	fprintf(DbgFp, "%02d:%02d:%02d.%06ld   ", tmp->tm_hour, tmp->tm_min,
    106 	        tmp->tm_sec, rconn->tstamp.tv_usec);
    107 
    108 	/* display src or dst addr and information about network interface */
    109 	fprintf(DbgFp, "Addr: %s   Intf: %s\n", EnetStr(rconn), IntfName);
    110 
    111 	rmp = &rconn->rmp;
    112 
    113 	/* display IEEE 802.2 Logical Link Control header */
    114 	(void) fprintf(DbgFp, "\t802.2 LLC: DSAP:%x SSAP:%x CTRL:%x\n",
    115 	               rmp->hp_llc.dsap, rmp->hp_llc.ssap, rmp->hp_llc.cntrl);
    116 
    117 	/* display HP extensions to 802.2 Logical Link Control header */
    118 	(void) fprintf(DbgFp, "\tHP Ext:    DXSAP:%x SXSAP:%x\n",
    119 	               rmp->hp_llc.dxsap, rmp->hp_llc.sxsap);
    120 
    121 	/*
    122 	 *  Display information about RMP packet using type field to
    123 	 *  determine what kind of packet this is.
    124 	 */
    125 	switch(rmp->r_type) {
    126 		case RMP_BOOT_REQ:		/* boot request */
    127 			(void) fprintf(DbgFp, "\tBoot Request:");
    128 			GETWORD(rmp->r_brq.rmp_seqno, t);
    129 			if (rmp->r_brq.rmp_session == RMP_PROBESID) {
    130 				if (WORDZE(rmp->r_brq.rmp_seqno))
    131 					fputs(" (Send Server ID)", DbgFp);
    132 				else
    133 					fprintf(DbgFp," (Send Filename #%u)",t);
    134 			}
    135 			(void) fputc('\n', DbgFp);
    136 			(void) fprintf(DbgFp, BootFmt, rmp->r_brq.rmp_retcode,
    137 			        t, rmp->r_brq.rmp_session,
    138 			        rmp->r_brq.rmp_version);
    139 			(void) fprintf(DbgFp, "\n\t\tMachine Type: ");
    140 			for (i = 0; i < RMP_MACHLEN; i++)
    141 				(void) fputc(rmp->r_brq.rmp_machtype[i], DbgFp);
    142 			DspFlnm(rmp->r_brq.rmp_flnmsize, &rmp->r_brq.rmp_flnm);
    143 			break;
    144 		case RMP_BOOT_REPL:		/* boot reply */
    145 			fprintf(DbgFp, "\tBoot Reply:\n");
    146 			GETWORD(rmp->r_brpl.rmp_seqno, t);
    147 			(void) fprintf(DbgFp, BootFmt, rmp->r_brpl.rmp_retcode,
    148 			        t, rmp->r_brpl.rmp_session,
    149 			        rmp->r_brpl.rmp_version);
    150 			DspFlnm(rmp->r_brpl.rmp_flnmsize,&rmp->r_brpl.rmp_flnm);
    151 			break;
    152 		case RMP_READ_REQ:		/* read request */
    153 			(void) fprintf(DbgFp, "\tRead Request:\n");
    154 			GETWORD(rmp->r_rrq.rmp_offset, t);
    155 			(void) fprintf(DbgFp, ReadFmt, rmp->r_rrq.rmp_retcode,
    156 			        t, rmp->r_rrq.rmp_session);
    157 			(void) fprintf(DbgFp, "\t\tNoOfBytes: %u\n",
    158 			        rmp->r_rrq.rmp_size);
    159 			break;
    160 		case RMP_READ_REPL:		/* read reply */
    161 			(void) fprintf(DbgFp, "\tRead Reply:\n");
    162 			GETWORD(rmp->r_rrpl.rmp_offset, t);
    163 			(void) fprintf(DbgFp, ReadFmt, rmp->r_rrpl.rmp_retcode,
    164 			        t, rmp->r_rrpl.rmp_session);
    165 			(void) fprintf(DbgFp, "\t\tNoOfBytesSent: %d\n",
    166 			        rconn->rmplen - RMPREADSIZE(0));
    167 			break;
    168 		case RMP_BOOT_DONE:		/* boot complete */
    169 			(void) fprintf(DbgFp, "\tBoot Complete:\n");
    170 			(void) fprintf(DbgFp, "\t\tRetCode:%u SessID:%x\n",
    171 			        rmp->r_done.rmp_retcode,
    172 			        rmp->r_done.rmp_session);
    173 			break;
    174 		default:			/* ??? */
    175 			(void) fprintf(DbgFp, "\tUnknown Type:(%d)\n",
    176 				rmp->r_type);
    177 	}
    178 	(void) fputc('\n', DbgFp);
    179 	(void) fflush(DbgFp);
    180 
    181 	(void) sigsetmask(omask);		/* reset old signal mask */
    182 }
    183 
    184 
    185 /*
    186 **  GetEtherAddr -- convert an RMP (Ethernet) address into a string.
    187 **
    188 **	An RMP BOOT packet has been received.  Look at the type field
    189 **	and process Boot Requests, Read Requests, and Boot Complete
    190 **	packets.  Any other type will be dropped with a warning msg.
    191 **
    192 **	Parameters:
    193 **		addr - array of RMP_ADDRLEN bytes.
    194 **
    195 **	Returns:
    196 **		Pointer to static string representation of `addr'.
    197 **
    198 **	Side Effects:
    199 **		None.
    200 **
    201 **	Warnings:
    202 **		- The return value points to a static buffer; it must
    203 **		  be copied if it's to be saved.
    204 **		- For speed, we assume a u_char consists of 8 bits.
    205 */
    206 char *
    207 GetEtherAddr(addr)
    208 	u_char *addr;
    209 {
    210 	static char Hex[] = "0123456789abcdef";
    211 	static char etherstr[RMP_ADDRLEN*3];
    212 	register int i;
    213 	register char *cp1, *cp2;
    214 
    215 	/*
    216 	 *  For each byte in `addr', convert it to "<hexchar><hexchar>:".
    217 	 *  The last byte does not get a trailing `:' appended.
    218 	 */
    219 	i = 0;
    220 	cp1 = (char *)addr;
    221 	cp2 = etherstr;
    222 	for(;;) {
    223 		*cp2++ = Hex[*cp1 >> 4 & 0xf];
    224 		*cp2++ = Hex[*cp1++ & 0xf];
    225 		if (++i == RMP_ADDRLEN)
    226 			break;
    227 		*cp2++ = ':';
    228 	}
    229 	*cp2 = '\0';
    230 
    231 	return(etherstr);
    232 }
    233 
    234 
    235 /*
    236 **  DispFlnm -- Print a string of bytes to DbgFp (often, a file name).
    237 **
    238 **	Parameters:
    239 **		size - number of bytes to print.
    240 **		flnm - address of first byte.
    241 **
    242 **	Returns:
    243 **		Nothing.
    244 **
    245 **	Side Effects:
    246 **		- Characters are sent to `DbgFp'.
    247 */
    248 void
    249 DspFlnm(size, flnm)
    250 	register u_int size;
    251 	register char *flnm;
    252 {
    253 	register int i;
    254 
    255 	(void) fprintf(DbgFp, "\n\t\tFile Name (%d): <", size);
    256 	for (i = 0; i < size; i++)
    257 		(void) fputc(*flnm++, DbgFp);
    258 	(void) fputs(">\n", DbgFp);
    259 }
    260 
    261 
    262 /*
    263 **  NewClient -- allocate memory for a new CLIENT.
    264 **
    265 **	Parameters:
    266 **		addr - RMP (Ethernet) address of new client.
    267 **
    268 **	Returns:
    269 **		Ptr to new CLIENT or NULL if we ran out of memory.
    270 **
    271 **	Side Effects:
    272 **		- Memory will be malloc'd for the new CLIENT.
    273 **		- If malloc() fails, a log message will be generated.
    274 */
    275 CLIENT *
    276 NewClient(addr)
    277 	u_char *addr;
    278 {
    279 	CLIENT *ctmp;
    280 
    281 	if ((ctmp = (CLIENT *) malloc(sizeof(CLIENT))) == NULL) {
    282 		syslog(LOG_ERR, "NewClient: out of memory (%s)",
    283 		       GetEtherAddr(addr));
    284 		return(NULL);
    285 	}
    286 
    287 	bzero(ctmp, sizeof(CLIENT));
    288 	bcopy(addr, &ctmp->addr[0], RMP_ADDRLEN);
    289 	return(ctmp);
    290 }
    291 
    292 /*
    293 **  FreeClient -- free linked list of Clients.
    294 **
    295 **	Parameters:
    296 **		None.
    297 **
    298 **	Returns:
    299 **		Nothing.
    300 **
    301 **	Side Effects:
    302 **		- All malloc'd memory associated with the linked list of
    303 **		  CLIENTS will be free'd; `Clients' will be set to NULL.
    304 **
    305 **	Warnings:
    306 **		- This routine must be called with SIGHUP blocked.
    307 */
    308 void
    309 FreeClients()
    310 {
    311 	register CLIENT *ctmp;
    312 
    313 	while (Clients != NULL) {
    314 		ctmp = Clients;
    315 		Clients = Clients->next;
    316 		FreeClient(ctmp);
    317 	}
    318 }
    319 
    320 /*
    321 **  NewStr -- allocate memory for a character array.
    322 **
    323 **	Parameters:
    324 **		str - null terminated character array.
    325 **
    326 **	Returns:
    327 **		Ptr to new character array or NULL if we ran out of memory.
    328 **
    329 **	Side Effects:
    330 **		- Memory will be malloc'd for the new character array.
    331 **		- If malloc() fails, a log message will be generated.
    332 */
    333 char *
    334 NewStr(str)
    335 	char *str;
    336 {
    337 	char *stmp;
    338 
    339 	if ((stmp = (char *)malloc((unsigned) (strlen(str)+1))) == NULL) {
    340 		syslog(LOG_ERR, "NewStr: out of memory (%s)", str);
    341 		return(NULL);
    342 	}
    343 
    344 	(void) strcpy(stmp, str);
    345 	return(stmp);
    346 }
    347 
    348 /*
    349 **  To save time, NewConn and FreeConn maintain a cache of one RMPCONN
    350 **  in `LastFree' (defined below).
    351 */
    352 
    353 static RMPCONN *LastFree = NULL;
    354 
    355 /*
    356 **  NewConn -- allocate memory for a new RMPCONN connection.
    357 **
    358 **	Parameters:
    359 **		rconn - initialization template for new connection.
    360 **
    361 **	Returns:
    362 **		Ptr to new RMPCONN or NULL if we ran out of memory.
    363 **
    364 **	Side Effects:
    365 **		- Memory may be malloc'd for the new RMPCONN (if not cached).
    366 **		- If malloc() fails, a log message will be generated.
    367 */
    368 RMPCONN *
    369 NewConn(rconn)
    370 	RMPCONN *rconn;
    371 {
    372 	RMPCONN *rtmp;
    373 
    374 	if (LastFree == NULL) {		/* nothing cached; make a new one */
    375 		if ((rtmp = (RMPCONN *) malloc(sizeof(RMPCONN))) == NULL) {
    376 			syslog(LOG_ERR, "NewConn: out of memory (%s)",
    377 			       EnetStr(rconn));
    378 			return(NULL);
    379 		}
    380 	} else {			/* use the cached RMPCONN */
    381 		rtmp = LastFree;
    382 		LastFree = NULL;
    383 	}
    384 
    385 	/*
    386 	 *  Copy template into `rtmp', init file descriptor to `-1' and
    387 	 *  set ptr to next elem NULL.
    388 	 */
    389 	bcopy((char *)rconn, (char *)rtmp, sizeof(RMPCONN));
    390 	rtmp->bootfd = -1;
    391 	rtmp->next = NULL;
    392 
    393 	return(rtmp);
    394 }
    395 
    396 /*
    397 **  FreeConn -- Free memory associated with an RMPCONN connection.
    398 **
    399 **	Parameters:
    400 **		rtmp - ptr to RMPCONN to be free'd.
    401 **
    402 **	Returns:
    403 **		Nothing.
    404 **
    405 **	Side Effects:
    406 **		- Memory associated with `rtmp' may be free'd (or cached).
    407 **		- File desc associated with `rtmp->bootfd' will be closed.
    408 */
    409 void
    410 FreeConn(rtmp)
    411 	register RMPCONN *rtmp;
    412 {
    413 	/*
    414 	 *  If the file descriptor is in use, close the file.
    415 	 */
    416 	if (rtmp->bootfd >= 0) {
    417 		(void) close(rtmp->bootfd);
    418 		rtmp->bootfd = -1;
    419 	}
    420 
    421 	if (LastFree == NULL)		/* cache for next time */
    422 		rtmp = LastFree;
    423 	else				/* already one cached; free this one */
    424 		free((char *)rtmp);
    425 }
    426 
    427 /*
    428 **  FreeConns -- free linked list of RMPCONN connections.
    429 **
    430 **	Parameters:
    431 **		None.
    432 **
    433 **	Returns:
    434 **		Nothing.
    435 **
    436 **	Side Effects:
    437 **		- All malloc'd memory associated with the linked list of
    438 **		  connections will be free'd; `RmpConns' will be set to NULL.
    439 **		- If LastFree is != NULL, it too will be free'd & NULL'd.
    440 **
    441 **	Warnings:
    442 **		- This routine must be called with SIGHUP blocked.
    443 */
    444 void
    445 FreeConns()
    446 {
    447 	register RMPCONN *rtmp;
    448 
    449 	while (RmpConns != NULL) {
    450 		rtmp = RmpConns;
    451 		RmpConns = RmpConns->next;
    452 		FreeConn(rtmp);
    453 	}
    454 
    455 	if (LastFree != NULL) {
    456 		free((char *)LastFree);
    457 		LastFree = NULL;
    458 	}
    459 }
    460 
    461 /*
    462 **  AddConn -- Add a connection to the linked list of connections.
    463 **
    464 **	Parameters:
    465 **		rconn - connection to be added.
    466 **
    467 **	Returns:
    468 **		Nothing.
    469 **
    470 **	Side Effects:
    471 **		- RmpConn will point to new connection.
    472 **
    473 **	Warnings:
    474 **		- This routine must be called with SIGHUP blocked.
    475 */
    476 void
    477 AddConn(rconn)
    478 	register RMPCONN *rconn;
    479 {
    480 	if (RmpConns != NULL)
    481 		rconn->next = RmpConns;
    482 	RmpConns = rconn;
    483 }
    484 
    485 /*
    486 **  FindConn -- Find a connection in the linked list of connections.
    487 **
    488 **	We use the RMP (Ethernet) address as the basis for determining
    489 **	if this is the same connection.  According to the Remote Maint
    490 **	Protocol, we can only have one connection with any machine.
    491 **
    492 **	Parameters:
    493 **		rconn - connection to be found.
    494 **
    495 **	Returns:
    496 **		Matching connection from linked list or NULL if not found.
    497 **
    498 **	Side Effects:
    499 **		None.
    500 **
    501 **	Warnings:
    502 **		- This routine must be called with SIGHUP blocked.
    503 */
    504 RMPCONN *
    505 FindConn(rconn)
    506 	register RMPCONN *rconn;
    507 {
    508 	register RMPCONN *rtmp;
    509 
    510 	for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
    511 		if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
    512 		         (char *)&rtmp->rmp.hp_hdr.saddr[0], RMP_ADDRLEN) == 0)
    513 			break;
    514 
    515 	return(rtmp);
    516 }
    517 
    518 /*
    519 **  RemoveConn -- Remove a connection from the linked list of connections.
    520 **
    521 **	Parameters:
    522 **		rconn - connection to be removed.
    523 **
    524 **	Returns:
    525 **		Nothing.
    526 **
    527 **	Side Effects:
    528 **		- If found, an RMPCONN will cease to exist and it will
    529 **		  be removed from the linked list.
    530 **
    531 **	Warnings:
    532 **		- This routine must be called with SIGHUP blocked.
    533 */
    534 void
    535 RemoveConn(rconn)
    536 	register RMPCONN *rconn;
    537 {
    538 	register RMPCONN *thisrconn, *lastrconn;
    539 
    540 	if (RmpConns == rconn) {		/* easy case */
    541 		RmpConns = RmpConns->next;
    542 		FreeConn(rconn);
    543 	} else {				/* must traverse linked list */
    544 		lastrconn = RmpConns;			/* set back ptr */
    545 		thisrconn = lastrconn->next;		/* set current ptr */
    546 		while (thisrconn != NULL) {
    547 			if (rconn == thisrconn) {		/* found it */
    548 				lastrconn->next = thisrconn->next;
    549 				FreeConn(thisrconn);
    550 				break;
    551 			}
    552 			lastrconn = thisrconn;
    553 			thisrconn = thisrconn->next;
    554 		}
    555 	}
    556 }
    557