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