xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.routed/trace.c (revision 552:6a924c2e2442)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * Copyright (c) 1983, 1988, 1993
60Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
90Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
100Sstevel@tonic-gate  * are met:
110Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
120Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
130Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
140Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
150Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
160Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
170Sstevel@tonic-gate  *    must display the following acknowledgment:
180Sstevel@tonic-gate  *	This product includes software developed by the University of
190Sstevel@tonic-gate  *	California, Berkeley and its contributors.
200Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
210Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
220Sstevel@tonic-gate  *    without specific prior written permission.
230Sstevel@tonic-gate  *
240Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
250Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
260Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
270Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
280Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
290Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
300Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
310Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
320Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
330Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
340Sstevel@tonic-gate  * SUCH DAMAGE.
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  * $FreeBSD: src/sbin/routed/trace.c,v 1.6 2000/08/11 08:24:38 sheldonh Exp $
370Sstevel@tonic-gate  */
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #include "defs.h"
420Sstevel@tonic-gate #include "pathnames.h"
430Sstevel@tonic-gate #include <signal.h>
440Sstevel@tonic-gate #include <sys/stat.h>
450Sstevel@tonic-gate #include <sys/signal.h>
460Sstevel@tonic-gate #include <strings.h>
470Sstevel@tonic-gate #include <fcntl.h>
480Sstevel@tonic-gate #include <protocols/routed.h>
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #define	NRECORDS	50		/* size of circular trace buffer */
510Sstevel@tonic-gate 
520Sstevel@tonic-gate int	tracelevel, new_tracelevel;
530Sstevel@tonic-gate FILE	*ftrace = stdout;		/* output trace file */
540Sstevel@tonic-gate static const char *sigtrace_pat = "%s";
550Sstevel@tonic-gate static char savetracename[MAXPATHLEN+1];
560Sstevel@tonic-gate static char *ripcmds[RIPCMD_MAX] =
570Sstevel@tonic-gate 	{"#0", "REQUEST", "RESPONSE", "TRACEON", "TRACEOFF", "POLL",
580Sstevel@tonic-gate 	"POLLENTRY"};
590Sstevel@tonic-gate char	inittracename[MAXPATHLEN+1];
600Sstevel@tonic-gate static boolean_t file_trace;	/* 1=tracing to file, not stdout */
610Sstevel@tonic-gate 
620Sstevel@tonic-gate static void tmsg(const char *, ...);
630Sstevel@tonic-gate 
640Sstevel@tonic-gate const char *
650Sstevel@tonic-gate rip_strerror(int err)
660Sstevel@tonic-gate {
670Sstevel@tonic-gate 	const char *cp = strerror(err);
680Sstevel@tonic-gate 	static char msgbuf[64];
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	if (cp == NULL) {
710Sstevel@tonic-gate 		if (err == 0) {
720Sstevel@tonic-gate 			cp = "success";
730Sstevel@tonic-gate 		} else {
740Sstevel@tonic-gate 			(void) snprintf(msgbuf, sizeof (msgbuf),
750Sstevel@tonic-gate 			    "unknown error %d", err);
760Sstevel@tonic-gate 			cp = msgbuf;
770Sstevel@tonic-gate 		}
780Sstevel@tonic-gate 	}
790Sstevel@tonic-gate 	return (cp);
800Sstevel@tonic-gate }
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /* convert IP address to a string, but not into a single buffer */
830Sstevel@tonic-gate char *
840Sstevel@tonic-gate naddr_ntoa(in_addr_t a)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate #define	NUM_BUFS 4
870Sstevel@tonic-gate 	static int bufno;
880Sstevel@tonic-gate 	static struct {
890Sstevel@tonic-gate 	    char    str[INET_ADDRSTRLEN];	/* xxx.xxx.xxx.xxx\0 */
900Sstevel@tonic-gate 	} bufs[NUM_BUFS];
910Sstevel@tonic-gate 	char *s;
920Sstevel@tonic-gate 	struct in_addr addr;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	addr.s_addr = a;
950Sstevel@tonic-gate 	s = strcpy(bufs[bufno].str, inet_ntoa(addr));
960Sstevel@tonic-gate 	bufno = (bufno+1) % NUM_BUFS;
970Sstevel@tonic-gate 	return (s);
980Sstevel@tonic-gate #undef NUM_BUFS
990Sstevel@tonic-gate }
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate const char *
1030Sstevel@tonic-gate saddr_ntoa(struct sockaddr_storage *ss)
1040Sstevel@tonic-gate {
1050Sstevel@tonic-gate 	return (ss == NULL) ? "?" : naddr_ntoa(S_ADDR(ss));
1060Sstevel@tonic-gate }
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate static char *
1100Sstevel@tonic-gate ts(time_t secs)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate 	static char s[20];
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	secs += epoch.tv_sec;
1150Sstevel@tonic-gate 	(void) strftime(s, sizeof (s), "%T", localtime(&secs));
1160Sstevel@tonic-gate 	return (s);
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate static char *
1200Sstevel@tonic-gate ts_full(struct timeval *tv)
1210Sstevel@tonic-gate {
1220Sstevel@tonic-gate 	static char s[32];
1230Sstevel@tonic-gate 	time_t secs;
1240Sstevel@tonic-gate 	int len;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	secs = tv->tv_sec + epoch.tv_sec;
1270Sstevel@tonic-gate 	(void) strftime(s, sizeof (s), "%Y/%m/%d %T", localtime(&secs));
1280Sstevel@tonic-gate 	len = strlen(s);
1290Sstevel@tonic-gate 	(void) snprintf(s + len, sizeof (s) - len, ".%06ld", tv->tv_usec);
1300Sstevel@tonic-gate 	return (s);
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate /*
1340Sstevel@tonic-gate  * On each event, display a time stamp.
1350Sstevel@tonic-gate  * This assumes that 'now' is update once for each event, and
1360Sstevel@tonic-gate  * that at least now.tv_usec changes.
1370Sstevel@tonic-gate  */
1380Sstevel@tonic-gate static struct timeval lastlog_time;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate void
1410Sstevel@tonic-gate lastlog(void)
1420Sstevel@tonic-gate {
1430Sstevel@tonic-gate 	if (lastlog_time.tv_sec != now.tv_sec ||
1440Sstevel@tonic-gate 	    lastlog_time.tv_usec != now.tv_usec) {
1450Sstevel@tonic-gate 		(void) fprintf(ftrace, "-- %s --\n", ts_full(&now));
1460Sstevel@tonic-gate 		lastlog_time = now;
1470Sstevel@tonic-gate 	}
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate static void
1520Sstevel@tonic-gate tmsg(const char *p, ...)
1530Sstevel@tonic-gate {
1540Sstevel@tonic-gate 	va_list args;
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	if (ftrace != NULL) {
1570Sstevel@tonic-gate 		lastlog();
1580Sstevel@tonic-gate 		va_start(args, p);
1590Sstevel@tonic-gate 		(void) vfprintf(ftrace, p, args);
1600Sstevel@tonic-gate 		(void) fputc('\n', ftrace);
1610Sstevel@tonic-gate 		(void) fflush(ftrace);
1620Sstevel@tonic-gate 		(void) va_end(args);
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate void
1680Sstevel@tonic-gate trace_close(int zap_stdio)
1690Sstevel@tonic-gate {
1700Sstevel@tonic-gate 	int fd;
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	(void) fflush(stdout);
1740Sstevel@tonic-gate 	(void) fflush(stderr);
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	if (ftrace != NULL && zap_stdio) {
1770Sstevel@tonic-gate 		if (ftrace != stdout)
1780Sstevel@tonic-gate 			(void) fclose(ftrace);
1790Sstevel@tonic-gate 		ftrace = NULL;
1800Sstevel@tonic-gate 		fd = open("/dev/null", O_RDWR);
1810Sstevel@tonic-gate 		if (isatty(STDIN_FILENO))
1820Sstevel@tonic-gate 			(void) dup2(fd, STDIN_FILENO);
1830Sstevel@tonic-gate 		if (isatty(STDOUT_FILENO))
1840Sstevel@tonic-gate 			(void) dup2(fd, STDOUT_FILENO);
1850Sstevel@tonic-gate 		if (isatty(STDERR_FILENO))
1860Sstevel@tonic-gate 			(void) dup2(fd, STDERR_FILENO);
1870Sstevel@tonic-gate 		(void) close(fd);
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 	lastlog_time.tv_sec = 0;
1900Sstevel@tonic-gate }
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate void
1940Sstevel@tonic-gate trace_flush(void)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate 	if (ftrace != NULL) {
1970Sstevel@tonic-gate 		(void) fflush(ftrace);
1980Sstevel@tonic-gate 		if (ferror(ftrace))
1990Sstevel@tonic-gate 			trace_off("tracing off: %s",
2000Sstevel@tonic-gate 			    rip_strerror(ferror(ftrace)));
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate void
2060Sstevel@tonic-gate trace_off(const char *p, ...)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate 	va_list args;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	if (ftrace != NULL) {
2120Sstevel@tonic-gate 		lastlog();
2130Sstevel@tonic-gate 		va_start(args, p);
2140Sstevel@tonic-gate 		(void) vfprintf(ftrace, p, args);
2150Sstevel@tonic-gate 		(void) fputc('\n', ftrace);
2160Sstevel@tonic-gate 		(void) va_end(args);
2170Sstevel@tonic-gate 	}
2180Sstevel@tonic-gate 	trace_close(file_trace);
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	new_tracelevel = tracelevel = 0;
2210Sstevel@tonic-gate }
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate /* log a change in tracing */
2250Sstevel@tonic-gate void
2260Sstevel@tonic-gate tracelevel_msg(const char *pat,
2270Sstevel@tonic-gate     int dump)		/* -1=no dump, 0=default, 1=force */
2280Sstevel@tonic-gate {
2290Sstevel@tonic-gate 	static const char *off_msgs[MAX_TRACELEVEL] = {
2300Sstevel@tonic-gate 		"Tracing actions stopped",
2310Sstevel@tonic-gate 		"Tracing packets stopped",
2320Sstevel@tonic-gate 		"Tracing packet contents stopped",
2330Sstevel@tonic-gate 		"Tracing kernel changes stopped",
2340Sstevel@tonic-gate 		"Tracing routing socket messages stopped",
2350Sstevel@tonic-gate 	};
2360Sstevel@tonic-gate 	static const char *on_msgs[MAX_TRACELEVEL] = {
2370Sstevel@tonic-gate 		"Tracing actions started",
2380Sstevel@tonic-gate 		"Tracing packets started",
2390Sstevel@tonic-gate 		"Tracing packet contents started",
2400Sstevel@tonic-gate 		"Tracing kernel changes started",
2410Sstevel@tonic-gate 		"Tracing routing socket messages started",
2420Sstevel@tonic-gate 	};
2430Sstevel@tonic-gate 	uint_t old_tracelevel = tracelevel;
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	if (new_tracelevel < 0)
2470Sstevel@tonic-gate 		new_tracelevel = 0;
2480Sstevel@tonic-gate 	else if (new_tracelevel > MAX_TRACELEVEL)
2490Sstevel@tonic-gate 		new_tracelevel = MAX_TRACELEVEL;
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	if (new_tracelevel < tracelevel) {
2520Sstevel@tonic-gate 		if (new_tracelevel <= 0) {
2530Sstevel@tonic-gate 			trace_off(pat, off_msgs[0]);
2540Sstevel@tonic-gate 		} else {
2550Sstevel@tonic-gate 			do {
2560Sstevel@tonic-gate 				tmsg(pat, off_msgs[tracelevel]);
2570Sstevel@tonic-gate 			} while (--tracelevel != new_tracelevel);
2580Sstevel@tonic-gate 		}
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	} else if (new_tracelevel > tracelevel) {
2610Sstevel@tonic-gate 		do {
2620Sstevel@tonic-gate 			tmsg(pat, on_msgs[tracelevel++]);
2630Sstevel@tonic-gate 		} while (tracelevel != new_tracelevel);
2640Sstevel@tonic-gate 	}
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	if (dump > 0 ||
2670Sstevel@tonic-gate 	    (dump == 0 && old_tracelevel == 0 && tracelevel != 0))
2680Sstevel@tonic-gate 		trace_dump();
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate void
2720Sstevel@tonic-gate set_tracefile(const char *filename,
2730Sstevel@tonic-gate     const char *pat,
2740Sstevel@tonic-gate     int dump)			/* -1=no dump, 0=default, 1=force */
2750Sstevel@tonic-gate {
2760Sstevel@tonic-gate 	struct stat stbuf;
2770Sstevel@tonic-gate 	struct stat stbuf2;
2780Sstevel@tonic-gate 	FILE *n_ftrace;
2790Sstevel@tonic-gate 	const char *fn;
2800Sstevel@tonic-gate 	int nfd;
2810Sstevel@tonic-gate 	boolean_t allow_create;
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 	/*
2840Sstevel@tonic-gate 	 * main() calls this routine with "dump == -1".  All others
2850Sstevel@tonic-gate 	 * call it with 0, so we take dump == -1 to mean "can create
2860Sstevel@tonic-gate 	 * the file."
2870Sstevel@tonic-gate 	 */
2880Sstevel@tonic-gate 	allow_create = (dump == -1);
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	/*
2910Sstevel@tonic-gate 	 * Allow a null filename to increase the level if the trace file
2920Sstevel@tonic-gate 	 * is already open or if coming from a trusted source, such as
2930Sstevel@tonic-gate 	 * a signal or the command line.
2940Sstevel@tonic-gate 	 */
2950Sstevel@tonic-gate 	if (filename == NULL || filename[0] == '\0') {
2960Sstevel@tonic-gate 		filename = NULL;
2970Sstevel@tonic-gate 		if (ftrace == NULL) {
2980Sstevel@tonic-gate 			if (inittracename[0] == '\0') {
2990Sstevel@tonic-gate 				msglog("missing trace file name");
3000Sstevel@tonic-gate 				return;
3010Sstevel@tonic-gate 			}
3020Sstevel@tonic-gate 			fn = inittracename;
3030Sstevel@tonic-gate 		} else {
3040Sstevel@tonic-gate 			goto set_tracelevel;
3050Sstevel@tonic-gate 		}
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	} else if (strcmp(filename, "dump/../table") == 0) {
3080Sstevel@tonic-gate 		trace_dump();
3090Sstevel@tonic-gate 		return;
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	} else {
3120Sstevel@tonic-gate 		/*
3130Sstevel@tonic-gate 		 * Allow the file specified with "-T file" to be reopened,
3140Sstevel@tonic-gate 		 * but require all other names specified over the net to
3150Sstevel@tonic-gate 		 * match the official path.  The path can specify a directory
3160Sstevel@tonic-gate 		 * in which the file is to be created.
3170Sstevel@tonic-gate 		 */
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 		if (strcmp(filename, inittracename) != 0) {
3200Sstevel@tonic-gate 			if (strncmp(filename, PATH_TRACE,
3210Sstevel@tonic-gate 			    sizeof (PATH_TRACE)-1) != 0 ||
3220Sstevel@tonic-gate 			    (strstr(filename, "../") != NULL)) {
3230Sstevel@tonic-gate 				msglog("wrong trace file \"%s\"", filename);
3240Sstevel@tonic-gate 				return;
3250Sstevel@tonic-gate 			}
3260Sstevel@tonic-gate 			if (stat(PATH_TRACE, &stbuf) == -1) {
3270Sstevel@tonic-gate 				fn = PATH_TRACE;
3280Sstevel@tonic-gate 				goto missing_file;
3290Sstevel@tonic-gate 			}
3300Sstevel@tonic-gate 			if (filename[sizeof (PATH_TRACE) - 1] != '\0' &&
3310Sstevel@tonic-gate 			    (filename[sizeof (PATH_TRACE) - 1] != '/' ||
3320Sstevel@tonic-gate 			    !S_ISDIR(stbuf.st_mode))) {
3330Sstevel@tonic-gate 				goto bad_file_type;
3340Sstevel@tonic-gate 			}
3350Sstevel@tonic-gate 			if (S_ISDIR(stbuf.st_mode))
3360Sstevel@tonic-gate 				allow_create = _B_TRUE;
3370Sstevel@tonic-gate 		}
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 		fn = filename;
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 	/* fn cannot be null here */
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	/* If the new tracefile exists, it must be a regular file. */
3440Sstevel@tonic-gate 	if (lstat(fn, &stbuf) == -1) {
3450Sstevel@tonic-gate 		if (!allow_create)
3460Sstevel@tonic-gate 			goto missing_file;
3470Sstevel@tonic-gate 		nfd = open(fn, O_CREAT|O_EXCL|O_WRONLY, 0644);
3480Sstevel@tonic-gate 		if (nfd != -1 && fstat(nfd, &stbuf) == -1) {
3490Sstevel@tonic-gate 			(void) close(nfd);
3500Sstevel@tonic-gate 			goto missing_file;
3510Sstevel@tonic-gate 		}
3520Sstevel@tonic-gate 	} else if (S_ISREG(stbuf.st_mode)) {
3530Sstevel@tonic-gate 		nfd = open(fn, O_APPEND|O_WRONLY, 0644);
3540Sstevel@tonic-gate 	} else {
3550Sstevel@tonic-gate 		goto bad_file_type;
3560Sstevel@tonic-gate 	}
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	if (nfd == -1 || (n_ftrace = fdopen(nfd, "a")) == NULL) {
3590Sstevel@tonic-gate 		msglog("failed to open trace file \"%s\" %s", fn,
3600Sstevel@tonic-gate 		    rip_strerror(errno));
3610Sstevel@tonic-gate 		if (fn == inittracename)
3620Sstevel@tonic-gate 			inittracename[0] = '\0';
3630Sstevel@tonic-gate 		if (nfd != -1)
3640Sstevel@tonic-gate 			(void) close(nfd);
3650Sstevel@tonic-gate 		return;
3660Sstevel@tonic-gate 	}
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	if (fstat(nfd, &stbuf2) == -1 || !S_ISREG(stbuf2.st_mode) ||
3690Sstevel@tonic-gate 	    stbuf2.st_dev != stbuf.st_dev || stbuf2.st_ino != stbuf.st_ino) {
3700Sstevel@tonic-gate 		msglog("trace file \"%s\" moved", fn);
3710Sstevel@tonic-gate 		(void) fclose(n_ftrace);
3720Sstevel@tonic-gate 		return;
3730Sstevel@tonic-gate 	}
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	tmsg("switch to trace file %s", fn);
3760Sstevel@tonic-gate 	trace_close(file_trace = _B_TRUE);
3770Sstevel@tonic-gate 	(void) dup2(nfd, STDOUT_FILENO);
3780Sstevel@tonic-gate 	(void) dup2(nfd, STDERR_FILENO);
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	if (fn != savetracename)
3810Sstevel@tonic-gate 		(void) strlcpy(savetracename, fn, sizeof (savetracename) - 1);
3820Sstevel@tonic-gate 	ftrace = n_ftrace;
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate set_tracelevel:
3850Sstevel@tonic-gate 	if (new_tracelevel == 0 || filename == NULL)
3860Sstevel@tonic-gate 		new_tracelevel++;
3870Sstevel@tonic-gate 	tracelevel_msg(pat, dump != 0 ? dump : (filename != NULL));
3880Sstevel@tonic-gate 	return;
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate missing_file:
3910Sstevel@tonic-gate 	msglog("trace \"%s\" missing", fn);
3920Sstevel@tonic-gate 	return;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate bad_file_type:
3950Sstevel@tonic-gate 	msglog("wrong type (%#x) of trace file \"%s\"", stbuf.st_mode, fn);
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate /* ARGSUSED */
4000Sstevel@tonic-gate void
4010Sstevel@tonic-gate sigtrace_more(int s)
4020Sstevel@tonic-gate {
4030Sstevel@tonic-gate 	new_tracelevel++;
4040Sstevel@tonic-gate 	sigtrace_pat = "SIGUSR1: %s";
4050Sstevel@tonic-gate 	if (signal(s, sigtrace_more) == SIG_ERR)
4060Sstevel@tonic-gate 		msglog("signal: %s", rip_strerror(errno));
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate /* ARGSUSED */
4110Sstevel@tonic-gate void
4120Sstevel@tonic-gate sigtrace_less(int s)
4130Sstevel@tonic-gate {
4140Sstevel@tonic-gate 	new_tracelevel--;
4150Sstevel@tonic-gate 	sigtrace_pat = "SIGUSR2: %s";
4160Sstevel@tonic-gate 	if (signal(s, sigtrace_less) == SIG_ERR)
4170Sstevel@tonic-gate 		msglog("signal: %s", rip_strerror(errno));
4180Sstevel@tonic-gate }
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate /* ARGSUSED */
4210Sstevel@tonic-gate void
4220Sstevel@tonic-gate sigtrace_dump(int s)
4230Sstevel@tonic-gate {
4240Sstevel@tonic-gate 	trace_dump();
4250Sstevel@tonic-gate 	if (signal(s, sigtrace_dump) == SIG_ERR)
4260Sstevel@tonic-gate 		msglog("signal: %s", rip_strerror(errno));
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate /* Set tracing after a signal. */
4300Sstevel@tonic-gate void
4310Sstevel@tonic-gate set_tracelevel(void)
4320Sstevel@tonic-gate {
4330Sstevel@tonic-gate 	if (new_tracelevel == tracelevel)
4340Sstevel@tonic-gate 		return;
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	/*
4370Sstevel@tonic-gate 	 * If tracing entirely off, and there was no tracefile specified
4380Sstevel@tonic-gate 	 * on the command line, then leave it off.
4390Sstevel@tonic-gate 	 */
4400Sstevel@tonic-gate 	if (new_tracelevel > tracelevel && ftrace == NULL) {
4410Sstevel@tonic-gate 		if (savetracename[0] != '\0') {
4420Sstevel@tonic-gate 			set_tracefile(savetracename, sigtrace_pat, 0);
4430Sstevel@tonic-gate 		} else if (inittracename[0] != '\0') {
4440Sstevel@tonic-gate 			set_tracefile(inittracename, sigtrace_pat, 0);
4450Sstevel@tonic-gate 		} else {
4460Sstevel@tonic-gate 			new_tracelevel = 0;
4470Sstevel@tonic-gate 			return;
4480Sstevel@tonic-gate 		}
4490Sstevel@tonic-gate 	} else {
4500Sstevel@tonic-gate 		tracelevel_msg(sigtrace_pat, 0);
4510Sstevel@tonic-gate 	}
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate /* display an address */
4560Sstevel@tonic-gate char *
4570Sstevel@tonic-gate addrname(in_addr_t addr,	/* in network byte order */
4580Sstevel@tonic-gate     in_addr_t	mask,
4590Sstevel@tonic-gate     int	force)			/* 0=show mask if nonstandard, */
4600Sstevel@tonic-gate {					/*	1=always show mask, 2=never */
4610Sstevel@tonic-gate #define	NUM_BUFS 4
4620Sstevel@tonic-gate 	static int bufno;
4630Sstevel@tonic-gate 	static struct {
4640Sstevel@tonic-gate 	/*
4650Sstevel@tonic-gate 	 * this array can hold either of the following strings terminated
4660Sstevel@tonic-gate 	 * by a null character:
4670Sstevel@tonic-gate 	 * "xxx.xxx.xxx.xxx/xx"
4680Sstevel@tonic-gate 	 * "xxx.xxx.xxx.xxx (mask xxx.xxx.xxx.xxx)"
4690Sstevel@tonic-gate 	 *
4700Sstevel@tonic-gate 	 */
4710Sstevel@tonic-gate 	    char    str[2*INET_ADDRSTRLEN + sizeof (" (mask )")];
4720Sstevel@tonic-gate 	} bufs[NUM_BUFS];
4730Sstevel@tonic-gate 	char *s, *sp;
4740Sstevel@tonic-gate 	in_addr_t dmask;
4750Sstevel@tonic-gate 	int i, len;
4760Sstevel@tonic-gate 	struct in_addr tmp_addr;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	tmp_addr.s_addr = addr;
4790Sstevel@tonic-gate 	len = strlcpy(bufs[bufno].str, inet_ntoa(tmp_addr),
4800Sstevel@tonic-gate 	    sizeof (bufs[bufno].str));
4810Sstevel@tonic-gate 	s = bufs[bufno].str;
4820Sstevel@tonic-gate 	bufno = (bufno+1) % NUM_BUFS;
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	if (force == 1 || (force == 0 && mask != std_mask(addr))) {
4850Sstevel@tonic-gate 		sp = &s[strlen(s)];
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 		dmask = mask & -mask;
4880Sstevel@tonic-gate 		if (mask + dmask == 0) {
4890Sstevel@tonic-gate 			i = ffs(mask);
4900Sstevel@tonic-gate 			(void) snprintf(sp,
4910Sstevel@tonic-gate 			    (sizeof (bufs[bufno].str) - len), "/%d",
4920Sstevel@tonic-gate 			    (NBBY * sizeof (in_addr_t) + 1) - i);
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		} else {
4950Sstevel@tonic-gate 			(void) snprintf(sp,
4960Sstevel@tonic-gate 			    (sizeof (bufs[bufno].str) - len), " (mask %s)",
4970Sstevel@tonic-gate 			    naddr_ntoa(htonl(mask)));
4980Sstevel@tonic-gate 		}
4990Sstevel@tonic-gate 	}
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	return (s);
5020Sstevel@tonic-gate #undef NUM_BUFS
5030Sstevel@tonic-gate }
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate /* display a bit-field */
5070Sstevel@tonic-gate struct or_bits {
5080Sstevel@tonic-gate 	uint8_t	origin;
5090Sstevel@tonic-gate 	const char *origin_name;
5100Sstevel@tonic-gate };
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate static struct or_bits origin_bits[] = {
5130Sstevel@tonic-gate 	{ RO_RIP,		"RIP" },
5140Sstevel@tonic-gate 	{ RO_RDISC,		"RDISC" },
5150Sstevel@tonic-gate 	{ RO_STATIC,		"STATIC" },
5160Sstevel@tonic-gate 	{ RO_LOOPBCK,		"LOOPBCK" },
5170Sstevel@tonic-gate 	{ RO_PTOPT,		"PTOPT" },
5180Sstevel@tonic-gate 	{ RO_NET_SYN,		"NET_SYN" },
5190Sstevel@tonic-gate 	{ RO_IF,		"IF" },
5200Sstevel@tonic-gate 	{ RO_FILE,		"FILE" },
5210Sstevel@tonic-gate 	{ RO_NONE,		"     " },
5220Sstevel@tonic-gate 	{ 0,			NULL}
5230Sstevel@tonic-gate };
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate /* display a bit-field */
5260Sstevel@tonic-gate struct bits {
527192Scarlsonj 	uint64_t	bits_mask;
528192Scarlsonj 	uint64_t	bits_clear;
529192Scarlsonj 	const char	*bits_name;
5300Sstevel@tonic-gate };
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate static struct bits if_bits[] = {
5330Sstevel@tonic-gate 	{ IFF_BROADCAST,	0,		"BROADCAST" },
5340Sstevel@tonic-gate 	{ IFF_DEBUG,		0,		"DEBUG" },
5350Sstevel@tonic-gate 	{ IFF_LOOPBACK,		0,		"LOOPBACK" },
5360Sstevel@tonic-gate 	{ IFF_POINTOPOINT,	0,		"POINTOPOINT" },
5370Sstevel@tonic-gate 	{ IFF_NOTRAILERS,	0,		"NOTRAILERS" },
5380Sstevel@tonic-gate 	{ IFF_RUNNING,		0,		"RUNNING" },
5390Sstevel@tonic-gate 	{ IFF_NOARP,		0,		"NOARP" },
5400Sstevel@tonic-gate 	{ IFF_PROMISC,		0,		"PROMISC" },
5410Sstevel@tonic-gate 	{ IFF_ALLMULTI,		0,		"ALLMULTI" },
5420Sstevel@tonic-gate 	{ IFF_INTELLIGENT,	0,		"INTELLIGENT" },
5430Sstevel@tonic-gate 	{ IFF_MULTICAST,	0,		"MULTICAST" },
5440Sstevel@tonic-gate 	{ IFF_MULTI_BCAST,	0,		"MULTI_BCAST" },
5450Sstevel@tonic-gate 	{ IFF_UNNUMBERED,	0,		"UNNUMBERED" },
5460Sstevel@tonic-gate 	{ IFF_DHCPRUNNING,	0,		"DHCP" },
5470Sstevel@tonic-gate 	{ IFF_PRIVATE,		0,		"PRIVATE" },
5480Sstevel@tonic-gate 	{ IFF_NOXMIT,		0,		"NOXMIT" },
5490Sstevel@tonic-gate 	{ IFF_NOLOCAL,		0,		"NOLOCAL" },
5500Sstevel@tonic-gate 	{ IFF_DEPRECATED,	0,		"DEPRECATED" },
5510Sstevel@tonic-gate 	{ IFF_ADDRCONF,		0,		"ADDRCONF" },
5520Sstevel@tonic-gate 	{ IFF_ROUTER,		0,		"ROUTER" },
5530Sstevel@tonic-gate 	{ IFF_NONUD,		0,		"NONUD" },
5540Sstevel@tonic-gate 	{ IFF_ANYCAST,		0,		"ANYCAST" },
5550Sstevel@tonic-gate 	{ IFF_NORTEXCH,		0,		"NORTEXCH" },
5560Sstevel@tonic-gate 	{ IFF_IPV4,		0,		"IPv4" },
5570Sstevel@tonic-gate 	{ IFF_IPV6,		0,		"IPv6" },
5580Sstevel@tonic-gate 	{ IFF_MIPRUNNING,	0,		"MIP" },
5590Sstevel@tonic-gate 	{ IFF_NOFAILOVER,	0,		"NOFAILOVER" },
5600Sstevel@tonic-gate 	{ IFF_FAILED,		0,		"FAILED" },
5610Sstevel@tonic-gate 	{ IFF_STANDBY,		0,		"STANDBY" },
5620Sstevel@tonic-gate 	{ IFF_INACTIVE,		0,		"INACTIVE" },
5630Sstevel@tonic-gate 	{ IFF_OFFLINE,		0,		"OFFLINE" },
5640Sstevel@tonic-gate 	{ IFF_XRESOLV,		0,		"XRESOLV" },
5650Sstevel@tonic-gate 	{ IFF_COS_ENABLED,	0,		"CoS" },
5660Sstevel@tonic-gate 	{ IFF_PREFERRED,	0,		"PREFERRED" },
5670Sstevel@tonic-gate 	{ IFF_TEMPORARY,	0,		"TEMPORARY" },
5680Sstevel@tonic-gate 	{ IFF_FIXEDMTU,		0,		"FIXEDMTU" },
5690Sstevel@tonic-gate 	{ IFF_VIRTUAL,		0,		"VIRTUAL"},
5700Sstevel@tonic-gate 	{ 0,			0,		NULL}
5710Sstevel@tonic-gate };
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate static struct bits is_bits[] = {
5740Sstevel@tonic-gate 	{ IS_ALIAS,		0,		"ALIAS" },
5750Sstevel@tonic-gate 	{ IS_SUBNET,		0,		"" },
5760Sstevel@tonic-gate 	{ IS_REMOTE,		(IS_NO_RDISC |
5770Sstevel@tonic-gate 				IS_BCAST_RDISC), "REMOTE" },
5780Sstevel@tonic-gate 	{ IS_PASSIVE,		(IS_NO_RDISC |
5790Sstevel@tonic-gate 				IS_NO_RIP |
5800Sstevel@tonic-gate 				IS_NO_SUPER_AG |
5810Sstevel@tonic-gate 				IS_PM_RDISC |
5820Sstevel@tonic-gate 				IS_NO_AG),	"PASSIVE" },
5830Sstevel@tonic-gate 	{ IS_EXTERNAL,		0,		"EXTERNAL" },
5840Sstevel@tonic-gate 	{ IS_CHECKED,		0,		"" },
5850Sstevel@tonic-gate 	{ IS_ALL_HOSTS,		0,		"" },
5860Sstevel@tonic-gate 	{ IS_ALL_ROUTERS,	0,		"" },
5870Sstevel@tonic-gate 	{ IS_DISTRUST,		0,		"DISTRUST" },
5880Sstevel@tonic-gate 	{ IS_BROKE,		IS_SICK,	"BROKEN" },
5890Sstevel@tonic-gate 	{ IS_SICK,		0,		"SICK" },
5900Sstevel@tonic-gate 	{ IS_DUP,		0,		"DUPLICATE" },
5910Sstevel@tonic-gate 	{ IS_REDIRECT_OK,	0,		"REDIRECT_OK" },
5920Sstevel@tonic-gate 	{ IS_NEED_NET_SYN,	0,		"" },
5930Sstevel@tonic-gate 	{ IS_NO_AG,		IS_NO_SUPER_AG,	"NO_AG" },
5940Sstevel@tonic-gate 	{ IS_NO_SUPER_AG,	0,		"NO_SUPER_AG" },
5950Sstevel@tonic-gate 	{ (IS_NO_RIPV1_IN |
5960Sstevel@tonic-gate 	    IS_NO_RIPV2_IN |
5970Sstevel@tonic-gate 	    IS_NO_RIPV1_OUT |
5980Sstevel@tonic-gate 	    IS_NO_RIPV2_OUT),	0,		"NO_RIP" },
5990Sstevel@tonic-gate 	{ (IS_NO_RIPV1_IN |
6000Sstevel@tonic-gate 	    IS_NO_RIPV1_OUT),	0,		"RIPV2" },
6010Sstevel@tonic-gate 	{ IS_NO_RIPV1_IN,	0,		"NO_RIPV1_IN" },
6020Sstevel@tonic-gate 	{ IS_NO_RIPV2_IN,	0,		"NO_RIPV2_IN" },
6030Sstevel@tonic-gate 	{ IS_NO_RIPV1_OUT,	0,		"NO_RIPV1_OUT" },
6040Sstevel@tonic-gate 	{ IS_NO_RIPV2_OUT,	0,		"NO_RIPV2_OUT" },
6050Sstevel@tonic-gate 	{ IS_NO_RIP_MCAST,	0,		"NO_RIP_MCAST" },
6060Sstevel@tonic-gate 	{ (IS_NO_ADV_IN |
6070Sstevel@tonic-gate 	    IS_NO_SOL_OUT |
6080Sstevel@tonic-gate 	    IS_NO_ADV_OUT),	IS_BCAST_RDISC,	"NO_RDISC" },
6090Sstevel@tonic-gate 	{ IS_NO_SOL_OUT,	0,		"NO_SOLICIT" },
6100Sstevel@tonic-gate 	{ IS_SOL_OUT,		0,		"SEND_SOLICIT" },
6110Sstevel@tonic-gate 	{ IS_NO_ADV_OUT,	IS_BCAST_RDISC,	"NO_RDISC_ADV" },
6120Sstevel@tonic-gate 	{ IS_ADV_OUT,		0,		"RDISC_ADV" },
6130Sstevel@tonic-gate 	{ IS_BCAST_RDISC,	0,		"BCAST_RDISC" },
6140Sstevel@tonic-gate 	{ IS_PM_RDISC,		0,		"" },
6150Sstevel@tonic-gate 	{ IS_NO_HOST,		0,		"NO_HOST" },
6160Sstevel@tonic-gate 	{ IS_SUPPRESS_RDISC,	0,		"SUPPRESS_RDISC" },
6170Sstevel@tonic-gate 	{ IS_FLUSH_RDISC,	0,		"FLUSH_RDISC" },
6180Sstevel@tonic-gate 	{ 0,			0,		NULL}
6190Sstevel@tonic-gate };
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate static struct bits rs_bits[] = {
6220Sstevel@tonic-gate 	{ RS_IF,		0,		"IF" },
6230Sstevel@tonic-gate 	{ RS_NET_INT,		RS_NET_SYN,	"NET_INT" },
6240Sstevel@tonic-gate 	{ RS_NET_SYN,		0,		"NET_SYN" },
6250Sstevel@tonic-gate 	{ RS_SUBNET,		0,		"" },
6260Sstevel@tonic-gate 	{ RS_LOCAL,		0,		"LOCAL" },
6270Sstevel@tonic-gate 	{ RS_MHOME,		0,		"MHOME" },
6280Sstevel@tonic-gate 	{ RS_STATIC,		0,		"STATIC" },
6290Sstevel@tonic-gate 	{ RS_NOPROPAGATE,	0,		"NOPROP" },
6300Sstevel@tonic-gate 	{ RS_BADIF,		0,		"BADIF" },
6310Sstevel@tonic-gate 	{ 0,			0,		NULL}
6320Sstevel@tonic-gate };
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate static struct bits ks_bits[] = {
6350Sstevel@tonic-gate 	{ KS_NEW,	0,		"NEW" },
6360Sstevel@tonic-gate 	{ KS_DELETE,	0,		"DELETE" },
6370Sstevel@tonic-gate 	{ KS_ADD,	0,		"ADD" },
6380Sstevel@tonic-gate 	{ KS_CHANGE,	0,		"CHANGE" },
6390Sstevel@tonic-gate 	{ KS_DEL_ADD,	0,		"DEL_ADD" },
6400Sstevel@tonic-gate 	{ KS_STATIC,	0,		"STATIC" },
6410Sstevel@tonic-gate 	{ KS_GATEWAY,	0,		"GATEWAY" },
6420Sstevel@tonic-gate 	{ KS_DYNAMIC,	0,		"DYNAMIC" },
6430Sstevel@tonic-gate 	{ KS_DELETED,	0,		"DELETED" },
6440Sstevel@tonic-gate 	{ KS_PRIVATE,	0,		"PRIVATE" },
6450Sstevel@tonic-gate 	{ KS_CHECK,	0,		"CHECK" },
6460Sstevel@tonic-gate 	{ KS_IF,	0,		"IF" },
6470Sstevel@tonic-gate 	{ KS_PASSIVE,	0,		"PASSIVE" },
6480Sstevel@tonic-gate 	{ KS_DEPRE_IF,	0,		"DEPRE_IF" },
6490Sstevel@tonic-gate 	{ KS_FILE,	0,		"FILE" },
6500Sstevel@tonic-gate 	{ 0,		0,		NULL}
6510Sstevel@tonic-gate };
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate static void
6540Sstevel@tonic-gate trace_bits(const struct bits *tbl,
655192Scarlsonj     uint64_t field,
6560Sstevel@tonic-gate     boolean_t force)
6570Sstevel@tonic-gate {
658192Scarlsonj 	uint64_t b;
6590Sstevel@tonic-gate 	char c;
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	if (force) {
6620Sstevel@tonic-gate 		(void) putc('<', ftrace);
6630Sstevel@tonic-gate 		c = '\0';
6640Sstevel@tonic-gate 	} else {
6650Sstevel@tonic-gate 		c = '<';
6660Sstevel@tonic-gate 	}
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	while (field != 0 &&
6690Sstevel@tonic-gate 	    (b = tbl->bits_mask) != 0) {
6700Sstevel@tonic-gate 		if ((b & field) == b) {
6710Sstevel@tonic-gate 			if (tbl->bits_name[0] != '\0') {
6720Sstevel@tonic-gate 				if (c != '\0')
6730Sstevel@tonic-gate 					(void) putc(c, ftrace);
6740Sstevel@tonic-gate 				(void) fprintf(ftrace, "%s", tbl->bits_name);
6750Sstevel@tonic-gate 				c = '|';
6760Sstevel@tonic-gate 			}
6770Sstevel@tonic-gate 			field &= ~(b | tbl->bits_clear);
6780Sstevel@tonic-gate 		}
6790Sstevel@tonic-gate 		tbl++;
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate 	if (field != 0) {
6820Sstevel@tonic-gate 		if (c != '\0')
6830Sstevel@tonic-gate 			(void) putc(c, ftrace);
684192Scarlsonj 		(void) fprintf(ftrace, "%#llx", field);
6850Sstevel@tonic-gate 		c = '|';
6860Sstevel@tonic-gate 	}
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	if (c != '<' || force)
6890Sstevel@tonic-gate 		(void) fputs("> ", ftrace);
6900Sstevel@tonic-gate }
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate static char *
6930Sstevel@tonic-gate trace_string(const struct bits *tbl, uint_t field, boolean_t force)
6940Sstevel@tonic-gate {
6950Sstevel@tonic-gate 	const struct bits *tbp;
6960Sstevel@tonic-gate 	char *sbuf, *cp, chr;
6970Sstevel@tonic-gate 	size_t slen;
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	/* minimum default string */
7000Sstevel@tonic-gate 	slen = sizeof ("<0x12345678>");
7010Sstevel@tonic-gate 	for (tbp = tbl; tbp->bits_mask != 0; tbp++)
7020Sstevel@tonic-gate 		if (tbp->bits_name[0] != '\0')
7030Sstevel@tonic-gate 			slen += strlen(tbp->bits_name) + 1;
7040Sstevel@tonic-gate 	if ((sbuf = malloc(slen)) == NULL)
7050Sstevel@tonic-gate 		return (NULL);
7060Sstevel@tonic-gate 	cp = sbuf;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	if (force) {
7090Sstevel@tonic-gate 		*cp++ = '<';
7100Sstevel@tonic-gate 		chr = '\0';
7110Sstevel@tonic-gate 	} else {
7120Sstevel@tonic-gate 		chr = '<';
7130Sstevel@tonic-gate 	}
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	while (field != 0 && tbl->bits_mask != 0) {
7160Sstevel@tonic-gate 		if ((tbl->bits_mask & field) == tbl->bits_mask) {
7170Sstevel@tonic-gate 			if (tbl->bits_name[0] != '\0') {
7180Sstevel@tonic-gate 				if (chr != '\0')
7190Sstevel@tonic-gate 					*cp++ = chr;
7200Sstevel@tonic-gate 				(void) strcpy(cp, tbl->bits_name);
7210Sstevel@tonic-gate 				cp += strlen(tbl->bits_name);
7220Sstevel@tonic-gate 				chr = '|';
7230Sstevel@tonic-gate 			}
7240Sstevel@tonic-gate 			field &= ~(tbl->bits_mask | tbl->bits_clear);
7250Sstevel@tonic-gate 		}
7260Sstevel@tonic-gate 		tbl++;
7270Sstevel@tonic-gate 	}
7280Sstevel@tonic-gate 	if (field != 0) {
7290Sstevel@tonic-gate 		if (chr != '\0')
7300Sstevel@tonic-gate 			*cp++ = chr;
7310Sstevel@tonic-gate 		cp += sprintf(cp, "%#x", field);
7320Sstevel@tonic-gate 		chr = '|';
7330Sstevel@tonic-gate 	}
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	if (chr != '<' || force)
7360Sstevel@tonic-gate 		*cp++ = '>';
7370Sstevel@tonic-gate 	*cp = '\0';
7380Sstevel@tonic-gate 	return (sbuf);
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate char *
7420Sstevel@tonic-gate if_bit_string(uint_t field, boolean_t force)
7430Sstevel@tonic-gate {
7440Sstevel@tonic-gate 	return (trace_string(if_bits, field, force));
7450Sstevel@tonic-gate }
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate char *
7480Sstevel@tonic-gate rtname(in_addr_t dst,
7490Sstevel@tonic-gate     in_addr_t mask,
7500Sstevel@tonic-gate     in_addr_t gate)
7510Sstevel@tonic-gate {
7520Sstevel@tonic-gate 	static char buf[sizeof ("xxx.xxx.xxx.xxx/xx-->xxx.xxx.xxx.xxx")];
7530Sstevel@tonic-gate 	int i;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "%-16s-->", addrname(dst, mask, 0));
7560Sstevel@tonic-gate 	i = strlen(buf);
7570Sstevel@tonic-gate 	(void) snprintf(&buf[i], (sizeof (buf) -i), "%-*s", 15+24-MAX(24, i),
7580Sstevel@tonic-gate 	    naddr_ntoa(gate));
7590Sstevel@tonic-gate 	return (buf);
7600Sstevel@tonic-gate }
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate static void
7640Sstevel@tonic-gate print_rts(struct rt_spare *rts,
7650Sstevel@tonic-gate     int force_metric,		/* -1=suppress, 0=default */
7660Sstevel@tonic-gate     int force_ifp,		/* -1=suppress, 0=default */
7670Sstevel@tonic-gate     int force_router,		/* -1=suppress, 0=default, 1=display */
7680Sstevel@tonic-gate     int force_tag,		/* -1=suppress, 0=default, 1=display */
7690Sstevel@tonic-gate     int force_time)		/* 0=suppress, 1=display */
7700Sstevel@tonic-gate {
7710Sstevel@tonic-gate 	int i;
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	if (force_metric >= 0)
7740Sstevel@tonic-gate 		(void) fprintf(ftrace, "metric=%-2d ", rts->rts_metric);
7750Sstevel@tonic-gate 	if (force_ifp >= 0)
7760Sstevel@tonic-gate 		(void) fprintf(ftrace, "%s ", (rts->rts_ifp == 0 ?
7770Sstevel@tonic-gate 		    "if?" : rts->rts_ifp->int_name));
7780Sstevel@tonic-gate 	if (force_router > 0 ||
7790Sstevel@tonic-gate 	    (force_router == 0 && rts->rts_router != rts->rts_gate))
7800Sstevel@tonic-gate 		(void) fprintf(ftrace, "router=%s ",
7810Sstevel@tonic-gate 		    naddr_ntoa(rts->rts_router));
7820Sstevel@tonic-gate 	if (force_time > 0)
7830Sstevel@tonic-gate 		(void) fprintf(ftrace, "%s ", ts(rts->rts_time));
7840Sstevel@tonic-gate 	if (force_tag > 0 ||
7850Sstevel@tonic-gate 	    (force_tag == 0 && rts->rts_tag != 0))
7860Sstevel@tonic-gate 		(void) fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag));
7870Sstevel@tonic-gate 	if (rts->rts_de_ag != 0) {
7880Sstevel@tonic-gate 		for (i = 1; (uint_t)(1 << i) <= rts->rts_de_ag; i++)
7890Sstevel@tonic-gate 			continue;
7900Sstevel@tonic-gate 		(void) fprintf(ftrace, "de_ag=%d ", i);
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 	(void) fprintf(ftrace, "flags 0x%x ", rts->rts_flags);
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate static void
7980Sstevel@tonic-gate print_rtsorigin(const struct or_bits *tbl, uint8_t route_origin)
7990Sstevel@tonic-gate {
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	uint8_t tblentry;
8020Sstevel@tonic-gate 	while ((tblentry = tbl->origin) != 0) {
8030Sstevel@tonic-gate 		if (tblentry == route_origin) {
8040Sstevel@tonic-gate 			(void) fprintf(ftrace, "origin=%s ", tbl->origin_name);
8050Sstevel@tonic-gate 		}
8060Sstevel@tonic-gate 		tbl++;
8070Sstevel@tonic-gate 	}
8080Sstevel@tonic-gate }
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate void
8120Sstevel@tonic-gate trace_if(const char *act, struct interface *ifp)
8130Sstevel@tonic-gate {
8140Sstevel@tonic-gate 	if (!TRACEACTIONS || ftrace == NULL)
8150Sstevel@tonic-gate 		return;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	lastlog();
8180Sstevel@tonic-gate 	(void) fprintf(ftrace, "%-3s interface %-4s #%-3d ", act,
8190Sstevel@tonic-gate 	    ifp->int_name,
8200Sstevel@tonic-gate 	    ifp->int_phys != NULL ? ifp->int_phys->phyi_index : 0);
8210Sstevel@tonic-gate 	(void) fprintf(ftrace, "%-15s-->%-15s",
8220Sstevel@tonic-gate 	    naddr_ntoa(ifp->int_addr),
8230Sstevel@tonic-gate 	    addrname(((ifp->int_if_flags & IFF_POINTOPOINT) ?
8240Sstevel@tonic-gate 	    ifp->int_dstaddr : htonl(ifp->int_net)),
8250Sstevel@tonic-gate 	    ifp->int_mask, 1));
8260Sstevel@tonic-gate 	if (ifp->int_metric != 0)
8270Sstevel@tonic-gate 		(void) fprintf(ftrace, " metric=%d", ifp->int_metric);
8280Sstevel@tonic-gate 	if (!IS_RIP_OUT_OFF(ifp->int_state) &&
8290Sstevel@tonic-gate 	    ifp->int_d_metric != 0)
8300Sstevel@tonic-gate 		(void) fprintf(ftrace, " fake_default=%d", ifp->int_d_metric);
8310Sstevel@tonic-gate 	(void) fputs("\n    ", ftrace);
8320Sstevel@tonic-gate 	trace_bits(if_bits, ifp->int_if_flags, _B_FALSE);
8330Sstevel@tonic-gate 	trace_bits(is_bits, ifp->int_state, _B_FALSE);
8340Sstevel@tonic-gate 	(void) fputc('\n', ftrace);
8350Sstevel@tonic-gate }
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate void
8380Sstevel@tonic-gate trace_khash(const struct khash *krt)
8390Sstevel@tonic-gate {
8400Sstevel@tonic-gate 	if (ftrace == NULL)
8410Sstevel@tonic-gate 		return;
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	lastlog();
8440Sstevel@tonic-gate 	(void) fprintf(ftrace, "  %-15s-->%-15s metric=%d ",
8450Sstevel@tonic-gate 	    addrname(krt->k_dst, krt->k_mask, 0),
8460Sstevel@tonic-gate 	    naddr_ntoa(krt->k_gate), krt->k_metric);
8470Sstevel@tonic-gate 	if (krt->k_ifp != NULL)
8480Sstevel@tonic-gate 		(void) fprintf(ftrace, "ifp %s ", krt->k_ifp->int_name);
8490Sstevel@tonic-gate 	else
8500Sstevel@tonic-gate 		(void) fprintf(ftrace, "ifp NULL ");
8510Sstevel@tonic-gate 	(void) fprintf(ftrace, "%s ", ts(krt->k_keep));
8520Sstevel@tonic-gate 	(void) fprintf(ftrace, "%s ", ts(krt->k_redirect_time));
8530Sstevel@tonic-gate 	trace_bits(ks_bits, krt->k_state, _B_TRUE);
8540Sstevel@tonic-gate 	(void) fputc('\n', ftrace);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate void
8580Sstevel@tonic-gate trace_dr(const struct dr *drp)
8590Sstevel@tonic-gate {
8600Sstevel@tonic-gate 	if (ftrace == NULL)
8610Sstevel@tonic-gate 		return;
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	lastlog();
8640Sstevel@tonic-gate 	(void) fprintf(ftrace, "  %-4s %-15s %s ",
8650Sstevel@tonic-gate 	    drp->dr_ifp != NULL ? drp->dr_ifp->int_name : "?",
8660Sstevel@tonic-gate 	    naddr_ntoa(drp->dr_gate), ts(drp->dr_ts));
8670Sstevel@tonic-gate 	(void) fprintf(ftrace, "%s %d %u\n", ts(drp->dr_life),
8680Sstevel@tonic-gate 	    SIGN_PREF(drp->dr_recv_pref), drp->dr_pref);
8690Sstevel@tonic-gate }
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate void
8720Sstevel@tonic-gate trace_upslot(struct rt_entry *rt,
8730Sstevel@tonic-gate     struct rt_spare *rts,
8740Sstevel@tonic-gate     struct rt_spare *new)
8750Sstevel@tonic-gate {
8760Sstevel@tonic-gate 	if (!TRACEACTIONS || ftrace == NULL)
8770Sstevel@tonic-gate 		return;
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	if (rts->rts_gate == new->rts_gate &&
8800Sstevel@tonic-gate 	    rts->rts_router == new->rts_router &&
8810Sstevel@tonic-gate 	    rts->rts_metric == new->rts_metric &&
8820Sstevel@tonic-gate 	    rts->rts_tag == new->rts_tag &&
8830Sstevel@tonic-gate 	    rts->rts_de_ag == new->rts_de_ag)
8840Sstevel@tonic-gate 		return;
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	lastlog();
8870Sstevel@tonic-gate 	if (new->rts_gate == 0) {
8880Sstevel@tonic-gate 		(void) fprintf(ftrace, "Del #%d %-35s ",
8890Sstevel@tonic-gate 		    (int)(rts - rt->rt_spares),
8900Sstevel@tonic-gate 		    rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate));
8910Sstevel@tonic-gate 		print_rts(rts, 0, 0, 0, 0,
8920Sstevel@tonic-gate 		    (rts != rt->rt_spares ||
8930Sstevel@tonic-gate 		    AGE_RT(rt->rt_state, rts->rts_origin, new->rts_ifp)));
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	} else if (rts->rts_gate != RIP_DEFAULT) {
8960Sstevel@tonic-gate 		(void) fprintf(ftrace, "Chg #%d %-35s ",
8970Sstevel@tonic-gate 		    (int)(rts - rt->rt_spares),
8980Sstevel@tonic-gate 		    rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate));
8990Sstevel@tonic-gate 		print_rts(rts, 0, 0,
9000Sstevel@tonic-gate 		    rts->rts_gate != new->rts_gate,
9010Sstevel@tonic-gate 		    rts->rts_tag != new->rts_tag,
9020Sstevel@tonic-gate 		    rts != rt->rt_spares || AGE_RT(rt->rt_state,
9030Sstevel@tonic-gate 			rts->rts_origin, rt->rt_ifp));
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 		(void) fprintf(ftrace, "\n       %19s%-16s ", "",
9060Sstevel@tonic-gate 		    (new->rts_gate != rts->rts_gate ?
9070Sstevel@tonic-gate 		    naddr_ntoa(new->rts_gate) : ""));
9080Sstevel@tonic-gate 		print_rts(new,
9090Sstevel@tonic-gate 		    ((new->rts_metric == rts->rts_metric) ? -1 : 0),
9100Sstevel@tonic-gate 		    ((new->rts_ifp == rts->rts_ifp) ? -1 : 0),
9110Sstevel@tonic-gate 		    0,
9120Sstevel@tonic-gate 		    rts->rts_tag != new->rts_tag,
9130Sstevel@tonic-gate 		    (new->rts_time != rts->rts_time &&
9140Sstevel@tonic-gate 		    (rts != rt->rt_spares ||
9150Sstevel@tonic-gate 		    AGE_RT(rt->rt_state, new->rts_origin, new->rts_ifp))));
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	} else {
9180Sstevel@tonic-gate 		(void) fprintf(ftrace, "Add #%d %-35s ",
9190Sstevel@tonic-gate 		    (int)(rts - rt->rt_spares),
9200Sstevel@tonic-gate 		    rtname(rt->rt_dst, rt->rt_mask, new->rts_gate));
9210Sstevel@tonic-gate 		print_rts(new, 0, 0, 0, 0,
9220Sstevel@tonic-gate 		    (rts != rt->rt_spares ||
9230Sstevel@tonic-gate 		    AGE_RT(rt->rt_state, new->rts_origin, new->rts_ifp)));
9240Sstevel@tonic-gate 	}
9250Sstevel@tonic-gate 	(void) fputc('\n', ftrace);
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate /* miscellaneous message checked by the caller */
9300Sstevel@tonic-gate void
9310Sstevel@tonic-gate trace_misc(const char *p, ...)
9320Sstevel@tonic-gate {
9330Sstevel@tonic-gate 	va_list args;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	if (ftrace == NULL)
9360Sstevel@tonic-gate 		return;
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	lastlog();
9390Sstevel@tonic-gate 	va_start(args, p);
9400Sstevel@tonic-gate 	(void) vfprintf(ftrace, p, args);
9410Sstevel@tonic-gate 	(void) fputc('\n', ftrace);
9420Sstevel@tonic-gate 	(void) va_end(args);
9430Sstevel@tonic-gate }
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate /* display a message if tracing actions */
9470Sstevel@tonic-gate void
9480Sstevel@tonic-gate trace_act(const char *p, ...)
9490Sstevel@tonic-gate {
9500Sstevel@tonic-gate 	va_list args;
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 	if (!TRACEACTIONS || ftrace == NULL)
9530Sstevel@tonic-gate 		return;
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	lastlog();
9560Sstevel@tonic-gate 	va_start(args, p);
9570Sstevel@tonic-gate 	(void) vfprintf(ftrace, p, args);
9580Sstevel@tonic-gate 	(void) fputc('\n', ftrace);
9590Sstevel@tonic-gate 	(void) va_end(args);
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate /* display a message if tracing packets */
9640Sstevel@tonic-gate void
9650Sstevel@tonic-gate trace_pkt(const char *p, ...)
9660Sstevel@tonic-gate {
9670Sstevel@tonic-gate 	va_list args;
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	if (!TRACEPACKETS || ftrace == NULL)
9700Sstevel@tonic-gate 		return;
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	lastlog();
9730Sstevel@tonic-gate 	va_start(args, p);
9740Sstevel@tonic-gate 	(void) vfprintf(ftrace, p, args);
9750Sstevel@tonic-gate 	(void) fputc('\n', ftrace);
9760Sstevel@tonic-gate 	(void) va_end(args);
9770Sstevel@tonic-gate }
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate void
9810Sstevel@tonic-gate trace_change(struct rt_entry *rt,
9820Sstevel@tonic-gate     uint16_t	state,
9830Sstevel@tonic-gate     struct	rt_spare *new,
9840Sstevel@tonic-gate     const char	*label)
9850Sstevel@tonic-gate {
9860Sstevel@tonic-gate 	if (ftrace == NULL)
9870Sstevel@tonic-gate 		return;
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	if (rt->rt_metric == new->rts_metric &&
9900Sstevel@tonic-gate 	    rt->rt_gate == new->rts_gate &&
9910Sstevel@tonic-gate 	    rt->rt_router == new->rts_router &&
9920Sstevel@tonic-gate 	    rt->rt_state == state &&
9930Sstevel@tonic-gate 	    rt->rt_tag == new->rts_tag &&
9940Sstevel@tonic-gate 	    rt->rt_de_ag == new->rts_de_ag)
9950Sstevel@tonic-gate 		return;
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	lastlog();
9980Sstevel@tonic-gate 	(void) fprintf(ftrace, "%s %-35s ",
9990Sstevel@tonic-gate 	    label,
10000Sstevel@tonic-gate 	    rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate));
10010Sstevel@tonic-gate 	print_rts(rt->rt_spares,
10020Sstevel@tonic-gate 	    0, 0, 0, 0, AGE_RT(rt->rt_state, rt->rt_spares->rts_origin,
10030Sstevel@tonic-gate 	    rt->rt_ifp));
10040Sstevel@tonic-gate 	print_rtsorigin(origin_bits, rt->rt_spares->rts_origin);
10050Sstevel@tonic-gate 	trace_bits(rs_bits, rt->rt_state, rt->rt_state != state);
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	(void) fprintf(ftrace, "\n%*s %19s%-16s ",
10080Sstevel@tonic-gate 	    strlen(label), "", "",
10090Sstevel@tonic-gate 	    (rt->rt_gate != new->rts_gate ?
10100Sstevel@tonic-gate 	    naddr_ntoa(new->rts_gate) : ""));
10110Sstevel@tonic-gate 	print_rts(new,
10120Sstevel@tonic-gate 	    ((new->rts_metric == rt->rt_metric) ? -1 : 0),
10130Sstevel@tonic-gate 	    ((new->rts_ifp == rt->rt_ifp) ? -1 : 0),
10140Sstevel@tonic-gate 	    0,
10150Sstevel@tonic-gate 	    rt->rt_tag != new->rts_tag,
10160Sstevel@tonic-gate 	    (rt->rt_time != new->rts_time &&
10170Sstevel@tonic-gate 	    AGE_RT(rt->rt_state, new->rts_origin, new->rts_ifp)));
10180Sstevel@tonic-gate 	if (rt->rt_state != state) {
10190Sstevel@tonic-gate 		print_rtsorigin(origin_bits, new->rts_origin);
10200Sstevel@tonic-gate 		trace_bits(rs_bits, state, _B_TRUE);
10210Sstevel@tonic-gate 	}
10220Sstevel@tonic-gate 	(void) fputc('\n', ftrace);
10230Sstevel@tonic-gate }
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate void
10270Sstevel@tonic-gate trace_add_del(const char *action, struct rt_entry *rt)
10280Sstevel@tonic-gate {
10290Sstevel@tonic-gate 	if (ftrace == NULL)
10300Sstevel@tonic-gate 		return;
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	lastlog();
10330Sstevel@tonic-gate 	(void) fprintf(ftrace, "%s    %-35s ",
10340Sstevel@tonic-gate 	    action,
10350Sstevel@tonic-gate 	    rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate));
10360Sstevel@tonic-gate 	print_rts(rt->rt_spares, 0, 0, 0, 0, AGE_RT(rt->rt_state,
10370Sstevel@tonic-gate 	    rt->rt_spares->rts_origin, rt->rt_ifp));
10380Sstevel@tonic-gate 	print_rtsorigin(origin_bits, rt->rt_spares->rts_origin);
10390Sstevel@tonic-gate 	trace_bits(rs_bits, rt->rt_state, _B_FALSE);
10400Sstevel@tonic-gate 	(void) fputc('\n', ftrace);
10410Sstevel@tonic-gate }
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate /* ARGSUSED */
10450Sstevel@tonic-gate static int
10460Sstevel@tonic-gate walk_trace(struct radix_node *rn,
10470Sstevel@tonic-gate     void *w)
10480Sstevel@tonic-gate {
10490Sstevel@tonic-gate #define	RT ((struct rt_entry *)rn)
10500Sstevel@tonic-gate 	struct rt_spare *rts;
10510Sstevel@tonic-gate 	int i;
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	(void) fprintf(ftrace, "  %-35s ",
10540Sstevel@tonic-gate 	    rtname(RT->rt_dst, RT->rt_mask, RT->rt_gate));
10550Sstevel@tonic-gate 	print_rts(&RT->rt_spares[0], 0, 0, 0, 0,
10560Sstevel@tonic-gate 	    AGE_RT(RT->rt_state, RT->rt_spares[0].rts_origin, RT->rt_ifp));
10570Sstevel@tonic-gate 	print_rtsorigin(origin_bits, RT->rt_spares[0].rts_origin);
10580Sstevel@tonic-gate 	trace_bits(rs_bits, RT->rt_state, _B_FALSE);
10590Sstevel@tonic-gate 	if (RT->rt_poison_time >= now_garbage &&
10600Sstevel@tonic-gate 	    RT->rt_poison_metric < RT->rt_metric)
10610Sstevel@tonic-gate 		(void) fprintf(ftrace, "pm=%d@%s",
10620Sstevel@tonic-gate 		    RT->rt_poison_metric, ts(RT->rt_poison_time));
1063*552Ssowmini 	(void) fprintf(ftrace, "%d spare slots", RT->rt_num_spares);
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	rts = &RT->rt_spares[1];
10660Sstevel@tonic-gate 	for (i = 1; i < RT->rt_num_spares; i++, rts++) {
10670Sstevel@tonic-gate 		if (rts->rts_gate != RIP_DEFAULT) {
10680Sstevel@tonic-gate 			(void) fprintf(ftrace, "\n    #%d%15s%-16s ",
10690Sstevel@tonic-gate 			    i, "", naddr_ntoa(rts->rts_gate));
10700Sstevel@tonic-gate 			print_rts(rts, 0, 0, 0, 0, 1);
10710Sstevel@tonic-gate 			print_rtsorigin(origin_bits, rts->rts_origin);
10720Sstevel@tonic-gate 		}
10730Sstevel@tonic-gate 	}
10740Sstevel@tonic-gate 	(void) fputc('\n', ftrace);
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	return (0);
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate void
10810Sstevel@tonic-gate trace_dump(void)
10820Sstevel@tonic-gate {
10830Sstevel@tonic-gate 	struct interface *ifp;
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	if (ftrace == NULL)
10860Sstevel@tonic-gate 		return;
10870Sstevel@tonic-gate 	lastlog();
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 	/*
10900Sstevel@tonic-gate 	 * Warning: the rtquery.trace.* family of STC tests depend on
10910Sstevel@tonic-gate 	 * the log file format here.  If you need to change this next
10920Sstevel@tonic-gate 	 * message, make sure that you change the TRACE_DUMP variable
10930Sstevel@tonic-gate 	 * as well.
10940Sstevel@tonic-gate 	 */
10950Sstevel@tonic-gate 	(void) fputs("current daemon state:\n", ftrace);
10960Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next)
10970Sstevel@tonic-gate 		trace_if("", ifp);
10980Sstevel@tonic-gate 	(void) fputs("Routes:\n", ftrace);
10990Sstevel@tonic-gate 	(void) rn_walktree(rhead, walk_trace, NULL);
11000Sstevel@tonic-gate 	(void) fputs("Kernel routes:\n", ftrace);
11010Sstevel@tonic-gate 	kern_dump();
11020Sstevel@tonic-gate 	(void) fputs("Discovered routers:\n", ftrace);
11030Sstevel@tonic-gate 	rdisc_dump();
11040Sstevel@tonic-gate }
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate void
11080Sstevel@tonic-gate trace_rip(const char *dir1, const char *dir2,
11090Sstevel@tonic-gate     struct sockaddr_in *who,
11100Sstevel@tonic-gate     struct interface *ifp,
11110Sstevel@tonic-gate     struct rip *msg,
11120Sstevel@tonic-gate     int size)			/* total size of message */
11130Sstevel@tonic-gate {
11140Sstevel@tonic-gate 	struct netinfo *n, *lim;
11150Sstevel@tonic-gate #define	NA ((struct netauth *)n)
11160Sstevel@tonic-gate 	int i, seen_route;
11170Sstevel@tonic-gate 	struct in_addr tmp_mask;
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate 	if (!TRACEPACKETS || ftrace == NULL)
11200Sstevel@tonic-gate 		return;
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	lastlog();
11230Sstevel@tonic-gate 	if (msg->rip_cmd >= RIPCMD_MAX || msg->rip_vers == 0) {
11240Sstevel@tonic-gate 		(void) fprintf(ftrace, "%s bad RIPv%d cmd=%d %s"
11250Sstevel@tonic-gate 		    " %s.%d size=%d\n",
11260Sstevel@tonic-gate 		    dir1, msg->rip_vers, msg->rip_cmd, dir2,
11270Sstevel@tonic-gate 		    naddr_ntoa(who->sin_addr.s_addr),
11280Sstevel@tonic-gate 		    ntohs(who->sin_port),
11290Sstevel@tonic-gate 		    size);
11300Sstevel@tonic-gate 		return;
11310Sstevel@tonic-gate 	}
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	(void) fprintf(ftrace, "%s RIPv%d %s %s %s.%d%s%s\n",
11340Sstevel@tonic-gate 	    dir1, msg->rip_vers, ripcmds[msg->rip_cmd], dir2,
11350Sstevel@tonic-gate 	    naddr_ntoa(who->sin_addr.s_addr), ntohs(who->sin_port),
11360Sstevel@tonic-gate 	    ifp ? " via " : "", ifp ? ifp->int_name : "");
11370Sstevel@tonic-gate 	if (!TRACECONTENTS)
11380Sstevel@tonic-gate 		return;
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	seen_route = 0;
11410Sstevel@tonic-gate 	switch (msg->rip_cmd) {
11420Sstevel@tonic-gate 	case RIPCMD_REQUEST:
11430Sstevel@tonic-gate 	case RIPCMD_RESPONSE:
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 		n = msg->rip_nets;
11460Sstevel@tonic-gate 		tmp_mask.s_addr = n->n_mask;
11470Sstevel@tonic-gate 		lim = n + (size - 4) / sizeof (struct netinfo);
11480Sstevel@tonic-gate 		for (; n < lim; n++) {
11490Sstevel@tonic-gate 			if (!seen_route &&
11500Sstevel@tonic-gate 			    n->n_family == RIP_AF_UNSPEC &&
11510Sstevel@tonic-gate 			    ntohl(n->n_metric) == HOPCNT_INFINITY &&
11520Sstevel@tonic-gate 			    msg->rip_cmd == RIPCMD_REQUEST &&
11530Sstevel@tonic-gate 			    (n+1 == lim ||
11540Sstevel@tonic-gate 			    (n+2 == lim &&
11550Sstevel@tonic-gate 			    (n+1)->n_family == RIP_AF_AUTH))) {
11560Sstevel@tonic-gate 				(void) fputs("\tQUERY ", ftrace);
11570Sstevel@tonic-gate 				if (n->n_dst != 0)
11580Sstevel@tonic-gate 					(void) fprintf(ftrace, "%s ",
11590Sstevel@tonic-gate 					    naddr_ntoa(n->n_dst));
11600Sstevel@tonic-gate 				if (n->n_mask != 0)
11610Sstevel@tonic-gate 					(void) fprintf(ftrace, "mask=%s ",
11620Sstevel@tonic-gate 					    inet_ntoa(tmp_mask));
11630Sstevel@tonic-gate 				if (n->n_nhop != 0)
11640Sstevel@tonic-gate 					(void) fprintf(ftrace, "nhop=%s ",
11650Sstevel@tonic-gate 					    naddr_ntoa(n->n_nhop));
11660Sstevel@tonic-gate 				if (n->n_tag != 0)
11670Sstevel@tonic-gate 					(void) fprintf(ftrace, "tag=%#x ",
11680Sstevel@tonic-gate 					    ntohs(n->n_tag));
11690Sstevel@tonic-gate 				(void) fputc('\n', ftrace);
11700Sstevel@tonic-gate 				continue;
11710Sstevel@tonic-gate 			}
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 			if (n->n_family == RIP_AF_AUTH) {
11740Sstevel@tonic-gate 				if (NA->a_type == RIP_AUTH_PW &&
11750Sstevel@tonic-gate 				    n == msg->rip_nets) {
11760Sstevel@tonic-gate 					(void) fprintf(ftrace, "\tPassword"
11770Sstevel@tonic-gate 					    " Authentication:"
11780Sstevel@tonic-gate 					    " \"%s\"\n",
11790Sstevel@tonic-gate 					    qstring(NA->au.au_pw,
11800Sstevel@tonic-gate 						RIP_AUTH_PW_LEN));
11810Sstevel@tonic-gate 					continue;
11820Sstevel@tonic-gate 				}
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 				if (NA->a_type == RIP_AUTH_MD5 &&
11850Sstevel@tonic-gate 				    n == msg->rip_nets) {
11860Sstevel@tonic-gate 					(void) fprintf(ftrace,
11870Sstevel@tonic-gate 					    "\tMD5 Auth"
11880Sstevel@tonic-gate 					    " pkt_len=%d KeyID=%u"
11890Sstevel@tonic-gate 					    " auth_len=%d"
11900Sstevel@tonic-gate 					    " seqno=%#lx"
11910Sstevel@tonic-gate 					    " rsvd=%#x,%#x\n",
11920Sstevel@tonic-gate 					    ntohs(NA->au.a_md5.md5_pkt_len),
11930Sstevel@tonic-gate 					    NA->au.a_md5.md5_keyid,
11940Sstevel@tonic-gate 					    NA->au.a_md5.md5_auth_len,
11950Sstevel@tonic-gate 					    (unsigned long)ntohl(NA->au.a_md5.
11960Sstevel@tonic-gate 						md5_seqno),
11970Sstevel@tonic-gate 					    ntohs(NA->au.a_md5.rsvd[0]),
11980Sstevel@tonic-gate 					    ntohs(NA->au.a_md5.rsvd[1]));
11990Sstevel@tonic-gate 					continue;
12000Sstevel@tonic-gate 				}
12010Sstevel@tonic-gate 				(void) fprintf(ftrace,
12020Sstevel@tonic-gate 				    "\tAuthentication type %d: ",
12030Sstevel@tonic-gate 				    ntohs(NA->a_type));
12040Sstevel@tonic-gate 				for (i = 0; i < (int)sizeof (NA->au.au_pw);
12050Sstevel@tonic-gate 				    i++)
12060Sstevel@tonic-gate 					(void) fprintf(ftrace, "%02x ",
12070Sstevel@tonic-gate 					    NA->au.au_pw[i]);
12080Sstevel@tonic-gate 				(void) fputc('\n', ftrace);
12090Sstevel@tonic-gate 				continue;
12100Sstevel@tonic-gate 			}
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 			seen_route = 1;
12130Sstevel@tonic-gate 			if (n->n_family != RIP_AF_INET) {
12140Sstevel@tonic-gate 				(void) fprintf(ftrace,
12150Sstevel@tonic-gate 				    "\t(af %d) %-18s mask=%s ",
12160Sstevel@tonic-gate 				    ntohs(n->n_family),
12170Sstevel@tonic-gate 				    naddr_ntoa(n->n_dst),
12180Sstevel@tonic-gate 				    inet_ntoa(tmp_mask));
12190Sstevel@tonic-gate 			} else if (msg->rip_vers == RIPv1) {
12200Sstevel@tonic-gate 				(void) fprintf(ftrace, "\t%-18s ",
12210Sstevel@tonic-gate 				    addrname(n->n_dst,
12220Sstevel@tonic-gate 					ntohl(n->n_mask),
12230Sstevel@tonic-gate 					n->n_mask == 0 ? 2 : 1));
12240Sstevel@tonic-gate 			} else {
12250Sstevel@tonic-gate 				(void) fprintf(ftrace, "\t%-18s ",
12260Sstevel@tonic-gate 				    addrname(n->n_dst,
12270Sstevel@tonic-gate 					ntohl(n->n_mask),
12280Sstevel@tonic-gate 					n->n_mask == 0 ? 2 : 0));
12290Sstevel@tonic-gate 			}
12300Sstevel@tonic-gate 			(void) fprintf(ftrace, "metric=%-2lu ",
12310Sstevel@tonic-gate 			    (unsigned long)ntohl(n->n_metric));
12320Sstevel@tonic-gate 			if (n->n_nhop != 0)
12330Sstevel@tonic-gate 				(void) fprintf(ftrace, " nhop=%s ",
12340Sstevel@tonic-gate 				    naddr_ntoa(n->n_nhop));
12350Sstevel@tonic-gate 			if (n->n_tag != 0)
12360Sstevel@tonic-gate 				(void) fprintf(ftrace, "tag=%#x",
12370Sstevel@tonic-gate 				    ntohs(n->n_tag));
12380Sstevel@tonic-gate 			(void) fputc('\n', ftrace);
12390Sstevel@tonic-gate 		}
12400Sstevel@tonic-gate 		if (size != (char *)n - (char *)msg)
12410Sstevel@tonic-gate 			(void) fprintf(ftrace, "truncated record, len %d\n",
12420Sstevel@tonic-gate 			    size);
12430Sstevel@tonic-gate 		break;
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 	case RIPCMD_TRACEON:
12460Sstevel@tonic-gate 		(void) fprintf(ftrace, "\tfile=\"%.*s\"\n", size-4,
12470Sstevel@tonic-gate 			msg->rip_tracefile);
12480Sstevel@tonic-gate 		break;
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	case RIPCMD_TRACEOFF:
12510Sstevel@tonic-gate 		break;
12520Sstevel@tonic-gate 	}
12530Sstevel@tonic-gate }
1254