155579Sbostic /* 255579Sbostic * Copyright (c) 1992 Regents of the University of California. 355579Sbostic * Copyright (c) 1988, 1992 The University of Utah and the Center 455579Sbostic * for Software Science (CSS). 555579Sbostic * All rights reserved. 655579Sbostic * 755579Sbostic * This code is derived from software contributed to Berkeley by 855579Sbostic * the Center for Software Science of the University of Utah Computer 955579Sbostic * Science Department. CSS requests users of this software to return 1055579Sbostic * to css-dist@cs.utah.edu any improvements that they make and grant 1155579Sbostic * CSS redistribution rights. 1255579Sbostic * 1355579Sbostic * %sccs.include.redist.c% 1455579Sbostic * 15*55600Sbostic * @(#)utils.c 5.2 (Berkeley) 07/23/92 1655579Sbostic * 1755579Sbostic * Utah $Hdr: utils.c 3.1 92/07/06$ 1855579Sbostic * Author: Jeff Forys, University of Utah CSS 1955579Sbostic */ 2055579Sbostic 2155579Sbostic #ifndef lint 22*55600Sbostic static char sccsid[] = "@(#)utils.c 5.2 (Berkeley) 07/23/92"; 2355579Sbostic #endif /* not lint */ 2455579Sbostic 25*55600Sbostic #include <sys/param.h> 2655579Sbostic 27*55600Sbostic #include <fcntl.h> 28*55600Sbostic #include <signal.h> 29*55600Sbostic #include <stdio.h> 30*55600Sbostic #include <stdlib.h> 31*55600Sbostic #include <string.h> 3255579Sbostic #include <syslog.h> 33*55600Sbostic #include <time.h> 34*55600Sbostic #include <unistd.h> 35*55600Sbostic #include "defs.h" 3655579Sbostic 3755579Sbostic /* 3855579Sbostic ** DispPkt -- Display the contents of an RMPCONN packet. 3955579Sbostic ** 4055579Sbostic ** Parameters: 4155579Sbostic ** rconn - packet to be displayed. 4255579Sbostic ** direct - direction packet is going (DIR_*). 4355579Sbostic ** 4455579Sbostic ** Returns: 4555579Sbostic ** Nothing. 4655579Sbostic ** 4755579Sbostic ** Side Effects: 4855579Sbostic ** None. 4955579Sbostic */ 50*55600Sbostic void 5155579Sbostic DispPkt(rconn, direct) 52*55600Sbostic RMPCONN *rconn; 53*55600Sbostic int direct; 5455579Sbostic { 5555579Sbostic static char BootFmt[] = "\t\tRetCode:%u SeqNo:%lx SessID:%x Vers:%u"; 5655579Sbostic static char ReadFmt[] = "\t\tRetCode:%u Offset:%lx SessID:%x\n"; 5755579Sbostic 5855579Sbostic struct tm *tmp; 5955579Sbostic register struct rmp_packet *rmp; 6055579Sbostic int i, omask; 6155579Sbostic u_int t; 6255579Sbostic 6355579Sbostic /* 6455579Sbostic * Since we will be working with RmpConns as well as DbgFp, we 6555579Sbostic * must block signals that can affect either. 6655579Sbostic */ 6755579Sbostic omask = sigblock(sigmask(SIGHUP)|sigmask(SIGUSR1)|sigmask(SIGUSR2)); 6855579Sbostic 6955579Sbostic if (DbgFp == NULL) { /* sanity */ 7055579Sbostic (void) sigsetmask(omask); 7155579Sbostic return; 7255579Sbostic } 7355579Sbostic 7455579Sbostic /* display direction packet is going using '>>>' or '<<<' */ 7555579Sbostic fputs((direct==DIR_RCVD)?"<<< ":(direct==DIR_SENT)?">>> ":"", DbgFp); 7655579Sbostic 7755579Sbostic /* display packet timestamp */ 7855579Sbostic tmp = localtime((time_t *)&rconn->tstamp.tv_sec); 7955579Sbostic fprintf(DbgFp, "%02d:%02d:%02d.%06ld ", tmp->tm_hour, tmp->tm_min, 8055579Sbostic tmp->tm_sec, rconn->tstamp.tv_usec); 8155579Sbostic 8255579Sbostic /* display src or dst addr and information about network interface */ 8355579Sbostic fprintf(DbgFp, "Addr: %s Intf: %s\n", EnetStr(rconn), IntfName); 8455579Sbostic 8555579Sbostic rmp = &rconn->rmp; 8655579Sbostic 8755579Sbostic /* display IEEE 802.2 Logical Link Control header */ 8855579Sbostic (void) fprintf(DbgFp, "\t802.2 LLC: DSAP:%x SSAP:%x CTRL:%x\n", 8955579Sbostic rmp->hp_llc.dsap, rmp->hp_llc.ssap, rmp->hp_llc.cntrl); 9055579Sbostic 9155579Sbostic /* display HP extensions to 802.2 Logical Link Control header */ 9255579Sbostic (void) fprintf(DbgFp, "\tHP Ext: DXSAP:%x SXSAP:%x\n", 9355579Sbostic rmp->hp_llc.dxsap, rmp->hp_llc.sxsap); 9455579Sbostic 9555579Sbostic /* 9655579Sbostic * Display information about RMP packet using type field to 9755579Sbostic * determine what kind of packet this is. 9855579Sbostic */ 9955579Sbostic switch(rmp->r_type) { 10055579Sbostic case RMP_BOOT_REQ: /* boot request */ 10155579Sbostic (void) fprintf(DbgFp, "\tBoot Request:"); 10255579Sbostic GETWORD(rmp->r_brq.rmp_seqno, t); 10355579Sbostic if (rmp->r_brq.rmp_session == RMP_PROBESID) { 10455579Sbostic if (WORDZE(rmp->r_brq.rmp_seqno)) 10555579Sbostic fputs(" (Send Server ID)", DbgFp); 10655579Sbostic else 10755579Sbostic fprintf(DbgFp," (Send Filename #%u)",t); 10855579Sbostic } 10955579Sbostic (void) fputc('\n', DbgFp); 11055579Sbostic (void) fprintf(DbgFp, BootFmt, rmp->r_brq.rmp_retcode, 11155579Sbostic t, rmp->r_brq.rmp_session, 11255579Sbostic rmp->r_brq.rmp_version); 11355579Sbostic (void) fprintf(DbgFp, "\n\t\tMachine Type: "); 11455579Sbostic for (i = 0; i < RMP_MACHLEN; i++) 11555579Sbostic (void) fputc(rmp->r_brq.rmp_machtype[i], DbgFp); 11655579Sbostic DspFlnm(rmp->r_brq.rmp_flnmsize, &rmp->r_brq.rmp_flnm); 11755579Sbostic break; 11855579Sbostic case RMP_BOOT_REPL: /* boot reply */ 11955579Sbostic fprintf(DbgFp, "\tBoot Reply:\n"); 12055579Sbostic GETWORD(rmp->r_brpl.rmp_seqno, t); 12155579Sbostic (void) fprintf(DbgFp, BootFmt, rmp->r_brpl.rmp_retcode, 12255579Sbostic t, rmp->r_brpl.rmp_session, 12355579Sbostic rmp->r_brpl.rmp_version); 12455579Sbostic DspFlnm(rmp->r_brpl.rmp_flnmsize,&rmp->r_brpl.rmp_flnm); 12555579Sbostic break; 12655579Sbostic case RMP_READ_REQ: /* read request */ 12755579Sbostic (void) fprintf(DbgFp, "\tRead Request:\n"); 12855579Sbostic GETWORD(rmp->r_rrq.rmp_offset, t); 12955579Sbostic (void) fprintf(DbgFp, ReadFmt, rmp->r_rrq.rmp_retcode, 13055579Sbostic t, rmp->r_rrq.rmp_session); 13155579Sbostic (void) fprintf(DbgFp, "\t\tNoOfBytes: %u\n", 13255579Sbostic rmp->r_rrq.rmp_size); 13355579Sbostic break; 13455579Sbostic case RMP_READ_REPL: /* read reply */ 13555579Sbostic (void) fprintf(DbgFp, "\tRead Reply:\n"); 13655579Sbostic GETWORD(rmp->r_rrpl.rmp_offset, t); 13755579Sbostic (void) fprintf(DbgFp, ReadFmt, rmp->r_rrpl.rmp_retcode, 13855579Sbostic t, rmp->r_rrpl.rmp_session); 13955579Sbostic (void) fprintf(DbgFp, "\t\tNoOfBytesSent: %d\n", 14055579Sbostic rconn->rmplen - RMPREADSIZE(0)); 14155579Sbostic break; 14255579Sbostic case RMP_BOOT_DONE: /* boot complete */ 14355579Sbostic (void) fprintf(DbgFp, "\tBoot Complete:\n"); 14455579Sbostic (void) fprintf(DbgFp, "\t\tRetCode:%u SessID:%x\n", 14555579Sbostic rmp->r_done.rmp_retcode, 14655579Sbostic rmp->r_done.rmp_session); 14755579Sbostic break; 14855579Sbostic default: /* ??? */ 14955579Sbostic (void) fprintf(DbgFp, "\tUnknown Type:(%d)\n", 15055579Sbostic rmp->r_type); 15155579Sbostic } 15255579Sbostic (void) fputc('\n', DbgFp); 15355579Sbostic (void) fflush(DbgFp); 15455579Sbostic 15555579Sbostic (void) sigsetmask(omask); /* reset old signal mask */ 15655579Sbostic } 15755579Sbostic 15855579Sbostic 15955579Sbostic /* 16055579Sbostic ** GetEtherAddr -- convert an RMP (Ethernet) address into a string. 16155579Sbostic ** 16255579Sbostic ** An RMP BOOT packet has been received. Look at the type field 16355579Sbostic ** and process Boot Requests, Read Requests, and Boot Complete 16455579Sbostic ** packets. Any other type will be dropped with a warning msg. 16555579Sbostic ** 16655579Sbostic ** Parameters: 16755579Sbostic ** addr - array of RMP_ADDRLEN bytes. 16855579Sbostic ** 16955579Sbostic ** Returns: 17055579Sbostic ** Pointer to static string representation of `addr'. 17155579Sbostic ** 17255579Sbostic ** Side Effects: 17355579Sbostic ** None. 17455579Sbostic ** 17555579Sbostic ** Warnings: 17655579Sbostic ** - The return value points to a static buffer; it must 17755579Sbostic ** be copied if it's to be saved. 17855579Sbostic ** - For speed, we assume a u_char consists of 8 bits. 17955579Sbostic */ 18055579Sbostic char * 18155579Sbostic GetEtherAddr(addr) 182*55600Sbostic u_char *addr; 18355579Sbostic { 18455579Sbostic static char Hex[] = "0123456789abcdef"; 18555579Sbostic static char etherstr[RMP_ADDRLEN*3]; 18655579Sbostic register int i; 18755579Sbostic register char *cp1, *cp2; 18855579Sbostic 18955579Sbostic /* 19055579Sbostic * For each byte in `addr', convert it to "<hexchar><hexchar>:". 19155579Sbostic * The last byte does not get a trailing `:' appended. 19255579Sbostic */ 19355579Sbostic i = 0; 19455579Sbostic cp1 = (char *)addr; 19555579Sbostic cp2 = etherstr; 19655579Sbostic for(;;) { 19755579Sbostic *cp2++ = Hex[*cp1 >> 4 & 0xf]; 19855579Sbostic *cp2++ = Hex[*cp1++ & 0xf]; 19955579Sbostic if (++i == RMP_ADDRLEN) 20055579Sbostic break; 20155579Sbostic *cp2++ = ':'; 20255579Sbostic } 20355579Sbostic *cp2 = '\0'; 20455579Sbostic 20555579Sbostic return(etherstr); 20655579Sbostic } 20755579Sbostic 20855579Sbostic 20955579Sbostic /* 21055579Sbostic ** DispFlnm -- Print a string of bytes to DbgFp (often, a file name). 21155579Sbostic ** 21255579Sbostic ** Parameters: 21355579Sbostic ** size - number of bytes to print. 21455579Sbostic ** flnm - address of first byte. 21555579Sbostic ** 21655579Sbostic ** Returns: 21755579Sbostic ** Nothing. 21855579Sbostic ** 21955579Sbostic ** Side Effects: 22055579Sbostic ** - Characters are sent to `DbgFp'. 22155579Sbostic */ 222*55600Sbostic void 22355579Sbostic DspFlnm(size, flnm) 224*55600Sbostic register u_int size; 225*55600Sbostic register char *flnm; 22655579Sbostic { 22755579Sbostic register int i; 22855579Sbostic 22955579Sbostic (void) fprintf(DbgFp, "\n\t\tFile Name (%d): <", size); 23055579Sbostic for (i = 0; i < size; i++) 23155579Sbostic (void) fputc(*flnm++, DbgFp); 23255579Sbostic (void) fputs(">\n", DbgFp); 23355579Sbostic } 23455579Sbostic 23555579Sbostic 23655579Sbostic /* 23755579Sbostic ** NewClient -- allocate memory for a new CLIENT. 23855579Sbostic ** 23955579Sbostic ** Parameters: 24055579Sbostic ** addr - RMP (Ethernet) address of new client. 24155579Sbostic ** 24255579Sbostic ** Returns: 24355579Sbostic ** Ptr to new CLIENT or NULL if we ran out of memory. 24455579Sbostic ** 24555579Sbostic ** Side Effects: 24655579Sbostic ** - Memory will be malloc'd for the new CLIENT. 24755579Sbostic ** - If malloc() fails, a log message will be generated. 24855579Sbostic */ 24955579Sbostic CLIENT * 25055579Sbostic NewClient(addr) 251*55600Sbostic u_char *addr; 25255579Sbostic { 25355579Sbostic CLIENT *ctmp; 25455579Sbostic 25555579Sbostic if ((ctmp = (CLIENT *) malloc(sizeof(CLIENT))) == NULL) { 25655579Sbostic syslog(LOG_ERR, "NewClient: out of memory (%s)", 25755579Sbostic GetEtherAddr(addr)); 25855579Sbostic return(NULL); 25955579Sbostic } 26055579Sbostic 261*55600Sbostic bzero(ctmp, sizeof(CLIENT)); 262*55600Sbostic bcopy(addr, &ctmp->addr[0], RMP_ADDRLEN); 26355579Sbostic return(ctmp); 26455579Sbostic } 26555579Sbostic 26655579Sbostic /* 26755579Sbostic ** FreeClient -- free linked list of Clients. 26855579Sbostic ** 26955579Sbostic ** Parameters: 27055579Sbostic ** None. 27155579Sbostic ** 27255579Sbostic ** Returns: 27355579Sbostic ** Nothing. 27455579Sbostic ** 27555579Sbostic ** Side Effects: 27655579Sbostic ** - All malloc'd memory associated with the linked list of 27755579Sbostic ** CLIENTS will be free'd; `Clients' will be set to NULL. 27855579Sbostic ** 27955579Sbostic ** Warnings: 28055579Sbostic ** - This routine must be called with SIGHUP blocked. 28155579Sbostic */ 282*55600Sbostic void 28355579Sbostic FreeClients() 28455579Sbostic { 28555579Sbostic register CLIENT *ctmp; 28655579Sbostic 28755579Sbostic while (Clients != NULL) { 28855579Sbostic ctmp = Clients; 28955579Sbostic Clients = Clients->next; 29055579Sbostic FreeClient(ctmp); 29155579Sbostic } 29255579Sbostic } 29355579Sbostic 29455579Sbostic /* 29555579Sbostic ** NewStr -- allocate memory for a character array. 29655579Sbostic ** 29755579Sbostic ** Parameters: 29855579Sbostic ** str - null terminated character array. 29955579Sbostic ** 30055579Sbostic ** Returns: 30155579Sbostic ** Ptr to new character array or NULL if we ran out of memory. 30255579Sbostic ** 30355579Sbostic ** Side Effects: 30455579Sbostic ** - Memory will be malloc'd for the new character array. 30555579Sbostic ** - If malloc() fails, a log message will be generated. 30655579Sbostic */ 30755579Sbostic char * 30855579Sbostic NewStr(str) 309*55600Sbostic char *str; 31055579Sbostic { 31155579Sbostic char *stmp; 31255579Sbostic 31355579Sbostic if ((stmp = (char *)malloc((unsigned) (strlen(str)+1))) == NULL) { 31455579Sbostic syslog(LOG_ERR, "NewStr: out of memory (%s)", str); 31555579Sbostic return(NULL); 31655579Sbostic } 31755579Sbostic 31855579Sbostic (void) strcpy(stmp, str); 31955579Sbostic return(stmp); 32055579Sbostic } 32155579Sbostic 32255579Sbostic /* 32355579Sbostic ** To save time, NewConn and FreeConn maintain a cache of one RMPCONN 32455579Sbostic ** in `LastFree' (defined below). 32555579Sbostic */ 32655579Sbostic 32755579Sbostic static RMPCONN *LastFree = NULL; 32855579Sbostic 32955579Sbostic /* 33055579Sbostic ** NewConn -- allocate memory for a new RMPCONN connection. 33155579Sbostic ** 33255579Sbostic ** Parameters: 33355579Sbostic ** rconn - initialization template for new connection. 33455579Sbostic ** 33555579Sbostic ** Returns: 33655579Sbostic ** Ptr to new RMPCONN or NULL if we ran out of memory. 33755579Sbostic ** 33855579Sbostic ** Side Effects: 33955579Sbostic ** - Memory may be malloc'd for the new RMPCONN (if not cached). 34055579Sbostic ** - If malloc() fails, a log message will be generated. 34155579Sbostic */ 34255579Sbostic RMPCONN * 34355579Sbostic NewConn(rconn) 344*55600Sbostic RMPCONN *rconn; 34555579Sbostic { 34655579Sbostic RMPCONN *rtmp; 34755579Sbostic 34855579Sbostic if (LastFree == NULL) { /* nothing cached; make a new one */ 34955579Sbostic if ((rtmp = (RMPCONN *) malloc(sizeof(RMPCONN))) == NULL) { 35055579Sbostic syslog(LOG_ERR, "NewConn: out of memory (%s)", 35155579Sbostic EnetStr(rconn)); 35255579Sbostic return(NULL); 35355579Sbostic } 35455579Sbostic } else { /* use the cached RMPCONN */ 35555579Sbostic rtmp = LastFree; 35655579Sbostic LastFree = NULL; 35755579Sbostic } 35855579Sbostic 35955579Sbostic /* 36055579Sbostic * Copy template into `rtmp', init file descriptor to `-1' and 36155579Sbostic * set ptr to next elem NULL. 36255579Sbostic */ 36355579Sbostic bcopy((char *)rconn, (char *)rtmp, sizeof(RMPCONN)); 36455579Sbostic rtmp->bootfd = -1; 36555579Sbostic rtmp->next = NULL; 36655579Sbostic 36755579Sbostic return(rtmp); 36855579Sbostic } 36955579Sbostic 37055579Sbostic /* 37155579Sbostic ** FreeConn -- Free memory associated with an RMPCONN connection. 37255579Sbostic ** 37355579Sbostic ** Parameters: 37455579Sbostic ** rtmp - ptr to RMPCONN to be free'd. 37555579Sbostic ** 37655579Sbostic ** Returns: 37755579Sbostic ** Nothing. 37855579Sbostic ** 37955579Sbostic ** Side Effects: 38055579Sbostic ** - Memory associated with `rtmp' may be free'd (or cached). 38155579Sbostic ** - File desc associated with `rtmp->bootfd' will be closed. 38255579Sbostic */ 383*55600Sbostic void 38455579Sbostic FreeConn(rtmp) 385*55600Sbostic register RMPCONN *rtmp; 38655579Sbostic { 38755579Sbostic /* 38855579Sbostic * If the file descriptor is in use, close the file. 38955579Sbostic */ 39055579Sbostic if (rtmp->bootfd >= 0) { 39155579Sbostic (void) close(rtmp->bootfd); 39255579Sbostic rtmp->bootfd = -1; 39355579Sbostic } 39455579Sbostic 39555579Sbostic if (LastFree == NULL) /* cache for next time */ 39655579Sbostic rtmp = LastFree; 39755579Sbostic else /* already one cached; free this one */ 39855579Sbostic free((char *)rtmp); 39955579Sbostic } 40055579Sbostic 40155579Sbostic /* 40255579Sbostic ** FreeConns -- free linked list of RMPCONN connections. 40355579Sbostic ** 40455579Sbostic ** Parameters: 40555579Sbostic ** None. 40655579Sbostic ** 40755579Sbostic ** Returns: 40855579Sbostic ** Nothing. 40955579Sbostic ** 41055579Sbostic ** Side Effects: 41155579Sbostic ** - All malloc'd memory associated with the linked list of 41255579Sbostic ** connections will be free'd; `RmpConns' will be set to NULL. 41355579Sbostic ** - If LastFree is != NULL, it too will be free'd & NULL'd. 41455579Sbostic ** 41555579Sbostic ** Warnings: 41655579Sbostic ** - This routine must be called with SIGHUP blocked. 41755579Sbostic */ 418*55600Sbostic void 41955579Sbostic FreeConns() 42055579Sbostic { 42155579Sbostic register RMPCONN *rtmp; 42255579Sbostic 42355579Sbostic while (RmpConns != NULL) { 42455579Sbostic rtmp = RmpConns; 42555579Sbostic RmpConns = RmpConns->next; 42655579Sbostic FreeConn(rtmp); 42755579Sbostic } 42855579Sbostic 42955579Sbostic if (LastFree != NULL) { 43055579Sbostic free((char *)LastFree); 43155579Sbostic LastFree = NULL; 43255579Sbostic } 43355579Sbostic } 43455579Sbostic 43555579Sbostic /* 43655579Sbostic ** AddConn -- Add a connection to the linked list of connections. 43755579Sbostic ** 43855579Sbostic ** Parameters: 43955579Sbostic ** rconn - connection to be added. 44055579Sbostic ** 44155579Sbostic ** Returns: 44255579Sbostic ** Nothing. 44355579Sbostic ** 44455579Sbostic ** Side Effects: 44555579Sbostic ** - RmpConn will point to new connection. 44655579Sbostic ** 44755579Sbostic ** Warnings: 44855579Sbostic ** - This routine must be called with SIGHUP blocked. 44955579Sbostic */ 450*55600Sbostic void 45155579Sbostic AddConn(rconn) 452*55600Sbostic register RMPCONN *rconn; 45355579Sbostic { 45455579Sbostic if (RmpConns != NULL) 45555579Sbostic rconn->next = RmpConns; 45655579Sbostic RmpConns = rconn; 45755579Sbostic } 45855579Sbostic 45955579Sbostic /* 46055579Sbostic ** FindConn -- Find a connection in the linked list of connections. 46155579Sbostic ** 46255579Sbostic ** We use the RMP (Ethernet) address as the basis for determining 46355579Sbostic ** if this is the same connection. According to the Remote Maint 46455579Sbostic ** Protocol, we can only have one connection with any machine. 46555579Sbostic ** 46655579Sbostic ** Parameters: 46755579Sbostic ** rconn - connection to be found. 46855579Sbostic ** 46955579Sbostic ** Returns: 47055579Sbostic ** Matching connection from linked list or NULL if not found. 47155579Sbostic ** 47255579Sbostic ** Side Effects: 47355579Sbostic ** None. 47455579Sbostic ** 47555579Sbostic ** Warnings: 47655579Sbostic ** - This routine must be called with SIGHUP blocked. 47755579Sbostic */ 47855579Sbostic RMPCONN * 47955579Sbostic FindConn(rconn) 480*55600Sbostic register RMPCONN *rconn; 48155579Sbostic { 48255579Sbostic register RMPCONN *rtmp; 48355579Sbostic 48455579Sbostic for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next) 48555579Sbostic if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0], 48655579Sbostic (char *)&rtmp->rmp.hp_hdr.saddr[0], RMP_ADDRLEN) == 0) 48755579Sbostic break; 48855579Sbostic 48955579Sbostic return(rtmp); 49055579Sbostic } 49155579Sbostic 49255579Sbostic /* 49355579Sbostic ** RemoveConn -- Remove a connection from the linked list of connections. 49455579Sbostic ** 49555579Sbostic ** Parameters: 49655579Sbostic ** rconn - connection to be removed. 49755579Sbostic ** 49855579Sbostic ** Returns: 49955579Sbostic ** Nothing. 50055579Sbostic ** 50155579Sbostic ** Side Effects: 50255579Sbostic ** - If found, an RMPCONN will cease to exist and it will 50355579Sbostic ** be removed from the linked list. 50455579Sbostic ** 50555579Sbostic ** Warnings: 50655579Sbostic ** - This routine must be called with SIGHUP blocked. 50755579Sbostic */ 508*55600Sbostic void 50955579Sbostic RemoveConn(rconn) 510*55600Sbostic register RMPCONN *rconn; 51155579Sbostic { 51255579Sbostic register RMPCONN *thisrconn, *lastrconn; 51355579Sbostic 51455579Sbostic if (RmpConns == rconn) { /* easy case */ 51555579Sbostic RmpConns = RmpConns->next; 51655579Sbostic FreeConn(rconn); 51755579Sbostic } else { /* must traverse linked list */ 51855579Sbostic lastrconn = RmpConns; /* set back ptr */ 51955579Sbostic thisrconn = lastrconn->next; /* set current ptr */ 52055579Sbostic while (thisrconn != NULL) { 52155579Sbostic if (rconn == thisrconn) { /* found it */ 52255579Sbostic lastrconn->next = thisrconn->next; 52355579Sbostic FreeConn(thisrconn); 52455579Sbostic break; 52555579Sbostic } 52655579Sbostic lastrconn = thisrconn; 52755579Sbostic thisrconn = thisrconn->next; 52855579Sbostic } 52955579Sbostic } 53055579Sbostic } 531