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