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