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