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@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@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