/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1988, 1992 The University of Utah and the Center4* for Software Science (CSS).5* Copyright (c) 1992, 19936* The Regents of the University of California. All rights reserved.7*8* This code is derived from software contributed to Berkeley by9* the Center for Software Science of the University of Utah Computer10* Science Department. CSS requests users of this software to return11* to [email protected] any improvements that they make and grant12* CSS redistribution rights.13*14* Redistribution and use in source and binary forms, with or without15* modification, are permitted provided that the following conditions16* are met:17* 1. Redistributions of source code must retain the above copyright18* notice, this list of conditions and the following disclaimer.19* 2. Redistributions in binary form must reproduce the above copyright20* notice, this list of conditions and the following disclaimer in the21* documentation and/or other materials provided with the distribution.22* 3. Neither the name of the University nor the names of its contributors23* may be used to endorse or promote products derived from this software24* without specific prior written permission.25*26* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND27* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE28* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE29* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE30* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL31* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS32* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)33* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT34* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY35* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF36* SUCH DAMAGE.37*38* From: Utah Hdr: utils.c 3.1 92/07/0639* Author: Jeff Forys, University of Utah CSS40*/4142#include <sys/param.h>43#include <sys/time.h>44#include <netinet/in.h>4546#include <fcntl.h>47#include <signal.h>48#include <stdio.h>49#include <stdlib.h>50#include <string.h>51#include <syslog.h>52#include <time.h>53#include <unistd.h>54#include "defs.h"5556/*57** DispPkt -- Display the contents of an RMPCONN packet.58**59** Parameters:60** rconn - packet to be displayed.61** direct - direction packet is going (DIR_*).62**63** Returns:64** Nothing.65**66** Side Effects:67** None.68*/69void70DispPkt(RMPCONN *rconn, int direct)71{72static const char BootFmt[] = "\t\tRetCode:%u SeqNo:%x SessID:%x Vers:%u";73static const char ReadFmt[] = "\t\tRetCode:%u Offset:%x SessID:%x\n";7475struct tm *tmp;76struct rmp_packet *rmp;77int i, omask;78u_int32_t t;7980/*81* Since we will be working with RmpConns as well as DbgFp, we82* must block signals that can affect either.83*/84omask = sigblock(sigmask(SIGHUP)|sigmask(SIGUSR1)|sigmask(SIGUSR2));8586if (DbgFp == NULL) { /* sanity */87(void) sigsetmask(omask);88return;89}9091/* display direction packet is going using '>>>' or '<<<' */92fputs((direct==DIR_RCVD)?"<<< ":(direct==DIR_SENT)?">>> ":"", DbgFp);9394/* display packet timestamp */95tmp = localtime((time_t *)&rconn->tstamp.tv_sec);96fprintf(DbgFp, "%02d:%02d:%02d.%06ld ", tmp->tm_hour, tmp->tm_min,97tmp->tm_sec, rconn->tstamp.tv_usec);9899/* display src or dst addr and information about network interface */100fprintf(DbgFp, "Addr: %s Intf: %s\n", EnetStr(rconn), IntfName);101102rmp = &rconn->rmp;103104/* display IEEE 802.2 Logical Link Control header */105(void) fprintf(DbgFp, "\t802.2 LLC: DSAP:%x SSAP:%x CTRL:%x\n",106rmp->hp_llc.dsap, rmp->hp_llc.ssap, ntohs(rmp->hp_llc.cntrl));107108/* display HP extensions to 802.2 Logical Link Control header */109(void) fprintf(DbgFp, "\tHP Ext: DXSAP:%x SXSAP:%x\n",110ntohs(rmp->hp_llc.dxsap), ntohs(rmp->hp_llc.sxsap));111112/*113* Display information about RMP packet using type field to114* determine what kind of packet this is.115*/116switch(rmp->r_type) {117case RMP_BOOT_REQ: /* boot request */118(void) fprintf(DbgFp, "\tBoot Request:");119GETWORD(rmp->r_brq.rmp_seqno, t);120if (ntohs(rmp->r_brq.rmp_session) == RMP_PROBESID) {121if (WORDZE(rmp->r_brq.rmp_seqno))122fputs(" (Send Server ID)", DbgFp);123else124fprintf(DbgFp," (Send Filename #%u)",t);125}126(void) fputc('\n', DbgFp);127(void) fprintf(DbgFp, BootFmt, rmp->r_brq.rmp_retcode,128t, ntohs(rmp->r_brq.rmp_session),129ntohs(rmp->r_brq.rmp_version));130(void) fprintf(DbgFp, "\n\t\tMachine Type: ");131for (i = 0; i < RMP_MACHLEN; i++)132(void) fputc(rmp->r_brq.rmp_machtype[i], DbgFp);133DspFlnm(rmp->r_brq.rmp_flnmsize, &rmp->r_brq.rmp_flnm);134break;135case RMP_BOOT_REPL: /* boot reply */136fprintf(DbgFp, "\tBoot Reply:\n");137GETWORD(rmp->r_brpl.rmp_seqno, t);138(void) fprintf(DbgFp, BootFmt, rmp->r_brpl.rmp_retcode,139t, ntohs(rmp->r_brpl.rmp_session),140ntohs(rmp->r_brpl.rmp_version));141DspFlnm(rmp->r_brpl.rmp_flnmsize,&rmp->r_brpl.rmp_flnm);142break;143case RMP_READ_REQ: /* read request */144(void) fprintf(DbgFp, "\tRead Request:\n");145GETWORD(rmp->r_rrq.rmp_offset, t);146(void) fprintf(DbgFp, ReadFmt, rmp->r_rrq.rmp_retcode,147t, ntohs(rmp->r_rrq.rmp_session));148(void) fprintf(DbgFp, "\t\tNoOfBytes: %u\n",149ntohs(rmp->r_rrq.rmp_size));150break;151case RMP_READ_REPL: /* read reply */152(void) fprintf(DbgFp, "\tRead Reply:\n");153GETWORD(rmp->r_rrpl.rmp_offset, t);154(void) fprintf(DbgFp, ReadFmt, rmp->r_rrpl.rmp_retcode,155t, ntohs(rmp->r_rrpl.rmp_session));156(void) fprintf(DbgFp, "\t\tNoOfBytesSent: %zu\n",157rconn->rmplen - RMPREADSIZE(0));158break;159case RMP_BOOT_DONE: /* boot complete */160(void) fprintf(DbgFp, "\tBoot Complete:\n");161(void) fprintf(DbgFp, "\t\tRetCode:%u SessID:%x\n",162rmp->r_done.rmp_retcode,163ntohs(rmp->r_done.rmp_session));164break;165default: /* ??? */166(void) fprintf(DbgFp, "\tUnknown Type:(%d)\n",167rmp->r_type);168}169(void) fputc('\n', DbgFp);170(void) fflush(DbgFp);171172(void) sigsetmask(omask); /* reset old signal mask */173}174175176/*177** GetEtherAddr -- convert an RMP (Ethernet) address into a string.178**179** An RMP BOOT packet has been received. Look at the type field180** and process Boot Requests, Read Requests, and Boot Complete181** packets. Any other type will be dropped with a warning msg.182**183** Parameters:184** addr - array of RMP_ADDRLEN bytes.185**186** Returns:187** Pointer to static string representation of `addr'.188**189** Side Effects:190** None.191**192** Warnings:193** - The return value points to a static buffer; it must194** be copied if it's to be saved.195*/196char *197GetEtherAddr(u_int8_t *addr)198{199static char Hex[] = "0123456789abcdef";200static char etherstr[RMP_ADDRLEN*3];201int i;202char *cp;203204/*205* For each byte in `addr', convert it to "<hexchar><hexchar>:".206* The last byte does not get a trailing `:' appended.207*/208i = 0;209cp = etherstr;210for(;;) {211*cp++ = Hex[*addr >> 4 & 0xf];212*cp++ = Hex[*addr++ & 0xf];213if (++i == RMP_ADDRLEN)214break;215*cp++ = ':';216}217*cp = '\0';218219return(etherstr);220}221222223/*224** DispFlnm -- Print a string of bytes to DbgFp (often, a file name).225**226** Parameters:227** size - number of bytes to print.228** flnm - address of first byte.229**230** Returns:231** Nothing.232**233** Side Effects:234** - Characters are sent to `DbgFp'.235*/236void237DspFlnm(u_int size, char *flnm)238{239int i;240241(void) fprintf(DbgFp, "\n\t\tFile Name (%u): <", size);242for (i = 0; i < size; i++)243(void) fputc(*flnm++, DbgFp);244(void) fputs(">\n", DbgFp);245}246247248/*249** NewClient -- allocate memory for a new CLIENT.250**251** Parameters:252** addr - RMP (Ethernet) address of new client.253**254** Returns:255** Ptr to new CLIENT or NULL if we ran out of memory.256**257** Side Effects:258** - Memory will be malloc'd for the new CLIENT.259** - If malloc() fails, a log message will be generated.260*/261CLIENT *262NewClient(u_int8_t *addr)263{264CLIENT *ctmp;265266if ((ctmp = (CLIENT *) malloc(sizeof(CLIENT))) == NULL) {267syslog(LOG_ERR, "NewClient: out of memory (%s)",268GetEtherAddr(addr));269return(NULL);270}271272memset(ctmp, 0, sizeof(CLIENT));273memmove(&ctmp->addr[0], addr, RMP_ADDRLEN);274return(ctmp);275}276277/*278** FreeClient -- free linked list of Clients.279**280** Parameters:281** None.282**283** Returns:284** Nothing.285**286** Side Effects:287** - All malloc'd memory associated with the linked list of288** CLIENTS will be free'd; `Clients' will be set to NULL.289**290** Warnings:291** - This routine must be called with SIGHUP blocked.292*/293void294FreeClients(void)295{296CLIENT *ctmp;297298while (Clients != NULL) {299ctmp = Clients;300Clients = Clients->next;301FreeClient(ctmp);302}303}304305/*306** NewStr -- allocate memory for a character array.307**308** Parameters:309** str - null terminated character array.310**311** Returns:312** Ptr to new character array or NULL if we ran out of memory.313**314** Side Effects:315** - Memory will be malloc'd for the new character array.316** - If malloc() fails, a log message will be generated.317*/318char *319NewStr(char *str)320{321char *stmp;322323if ((stmp = (char *)malloc((unsigned) (strlen(str)+1))) == NULL) {324syslog(LOG_ERR, "NewStr: out of memory (%s)", str);325return(NULL);326}327328(void) strcpy(stmp, str);329return(stmp);330}331332/*333** To save time, NewConn and FreeConn maintain a cache of one RMPCONN334** in `LastFree' (defined below).335*/336337static RMPCONN *LastFree = NULL;338339/*340** NewConn -- allocate memory for a new RMPCONN connection.341**342** Parameters:343** rconn - initialization template for new connection.344**345** Returns:346** Ptr to new RMPCONN or NULL if we ran out of memory.347**348** Side Effects:349** - Memory may be malloc'd for the new RMPCONN (if not cached).350** - If malloc() fails, a log message will be generated.351*/352RMPCONN *353NewConn(RMPCONN *rconn)354{355RMPCONN *rtmp;356357if (LastFree == NULL) { /* nothing cached; make a new one */358if ((rtmp = (RMPCONN *) malloc(sizeof(RMPCONN))) == NULL) {359syslog(LOG_ERR, "NewConn: out of memory (%s)",360EnetStr(rconn));361return(NULL);362}363} else { /* use the cached RMPCONN */364rtmp = LastFree;365LastFree = NULL;366}367368/*369* Copy template into `rtmp', init file descriptor to `-1' and370* set ptr to next elem NULL.371*/372memmove((char *)rtmp, (char *)rconn, sizeof(RMPCONN));373rtmp->bootfd = -1;374rtmp->next = NULL;375376return(rtmp);377}378379/*380** FreeConn -- Free memory associated with an RMPCONN connection.381**382** Parameters:383** rtmp - ptr to RMPCONN to be free'd.384**385** Returns:386** Nothing.387**388** Side Effects:389** - Memory associated with `rtmp' may be free'd (or cached).390** - File desc associated with `rtmp->bootfd' will be closed.391*/392void393FreeConn(RMPCONN *rtmp)394{395/*396* If the file descriptor is in use, close the file.397*/398if (rtmp->bootfd >= 0) {399(void) close(rtmp->bootfd);400rtmp->bootfd = -1;401}402403if (LastFree == NULL) /* cache for next time */404rtmp = LastFree;405else /* already one cached; free this one */406free((char *)rtmp);407}408409/*410** FreeConns -- free linked list of RMPCONN connections.411**412** Parameters:413** None.414**415** Returns:416** Nothing.417**418** Side Effects:419** - All malloc'd memory associated with the linked list of420** connections will be free'd; `RmpConns' will be set to NULL.421** - If LastFree is != NULL, it too will be free'd & NULL'd.422**423** Warnings:424** - This routine must be called with SIGHUP blocked.425*/426void427FreeConns(void)428{429RMPCONN *rtmp;430431while (RmpConns != NULL) {432rtmp = RmpConns;433RmpConns = RmpConns->next;434FreeConn(rtmp);435}436437if (LastFree != NULL) {438free((char *)LastFree);439LastFree = NULL;440}441}442443/*444** AddConn -- Add a connection to the linked list of connections.445**446** Parameters:447** rconn - connection to be added.448**449** Returns:450** Nothing.451**452** Side Effects:453** - RmpConn will point to new connection.454**455** Warnings:456** - This routine must be called with SIGHUP blocked.457*/458void459AddConn(RMPCONN *rconn)460{461if (RmpConns != NULL)462rconn->next = RmpConns;463RmpConns = rconn;464}465466/*467** FindConn -- Find a connection in the linked list of connections.468**469** We use the RMP (Ethernet) address as the basis for determining470** if this is the same connection. According to the Remote Maint471** Protocol, we can only have one connection with any machine.472**473** Parameters:474** rconn - connection to be found.475**476** Returns:477** Matching connection from linked list or NULL if not found.478**479** Side Effects:480** None.481**482** Warnings:483** - This routine must be called with SIGHUP blocked.484*/485RMPCONN *486FindConn(RMPCONN *rconn)487{488RMPCONN *rtmp;489490for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)491if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],492(char *)&rtmp->rmp.hp_hdr.saddr[0], RMP_ADDRLEN) == 0)493break;494495return(rtmp);496}497498/*499** RemoveConn -- Remove a connection from the linked list of connections.500**501** Parameters:502** rconn - connection to be removed.503**504** Returns:505** Nothing.506**507** Side Effects:508** - If found, an RMPCONN will cease to exist and it will509** be removed from the linked list.510**511** Warnings:512** - This routine must be called with SIGHUP blocked.513*/514void515RemoveConn(RMPCONN *rconn)516{517RMPCONN *thisrconn, *lastrconn;518519if (RmpConns == rconn) { /* easy case */520RmpConns = RmpConns->next;521FreeConn(rconn);522} else { /* must traverse linked list */523lastrconn = RmpConns; /* set back ptr */524thisrconn = lastrconn->next; /* set current ptr */525while (thisrconn != NULL) {526if (rconn == thisrconn) { /* found it */527lastrconn->next = thisrconn->next;528FreeConn(thisrconn);529break;530}531lastrconn = thisrconn;532thisrconn = thisrconn->next;533}534}535}536537538