utils.c revision 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