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