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