Home | History | Annotate | Download | only in in.routed
      1     0    stevel /*
      2  8485     Peter  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      3     0    stevel  * Use is subject to license terms.
      4     0    stevel  *
      5     0    stevel  * Copyright (c) 1983, 1988, 1993
      6     0    stevel  *	The Regents of the University of California.  All rights reserved.
      7     0    stevel  *
      8     0    stevel  * Redistribution and use in source and binary forms, with or without
      9     0    stevel  * modification, are permitted provided that the following conditions
     10     0    stevel  * are met:
     11     0    stevel  * 1. Redistributions of source code must retain the above copyright
     12     0    stevel  *    notice, this list of conditions and the following disclaimer.
     13     0    stevel  * 2. Redistributions in binary form must reproduce the above copyright
     14     0    stevel  *    notice, this list of conditions and the following disclaimer in the
     15     0    stevel  *    documentation and/or other materials provided with the distribution.
     16     0    stevel  * 3. All advertising materials mentioning features or use of this software
     17     0    stevel  *    must display the following acknowledgment:
     18     0    stevel  *	This product includes software developed by the University of
     19     0    stevel  *	California, Berkeley and its contributors.
     20     0    stevel  * 4. Neither the name of the University nor the names of its contributors
     21     0    stevel  *    may be used to endorse or promote products derived from this software
     22     0    stevel  *    without specific prior written permission.
     23     0    stevel  *
     24     0    stevel  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25     0    stevel  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26     0    stevel  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27     0    stevel  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28     0    stevel  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29     0    stevel  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30     0    stevel  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31     0    stevel  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32     0    stevel  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33     0    stevel  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34     0    stevel  * SUCH DAMAGE.
     35     0    stevel  *
     36     0    stevel  * $FreeBSD: src/sbin/routed/trace.c,v 1.6 2000/08/11 08:24:38 sheldonh Exp $
     37     0    stevel  */
     38     0    stevel 
     39     0    stevel #include "defs.h"
     40     0    stevel #include "pathnames.h"
     41     0    stevel #include <signal.h>
     42     0    stevel #include <sys/stat.h>
     43     0    stevel #include <sys/signal.h>
     44     0    stevel #include <strings.h>
     45     0    stevel #include <fcntl.h>
     46     0    stevel #include <protocols/routed.h>
     47     0    stevel 
     48     0    stevel #define	NRECORDS	50		/* size of circular trace buffer */
     49     0    stevel 
     50     0    stevel int	tracelevel, new_tracelevel;
     51     0    stevel FILE	*ftrace = stdout;		/* output trace file */
     52     0    stevel static const char *sigtrace_pat = "%s";
     53     0    stevel static char savetracename[MAXPATHLEN+1];
     54     0    stevel static char *ripcmds[RIPCMD_MAX] =
     55     0    stevel 	{"#0", "REQUEST", "RESPONSE", "TRACEON", "TRACEOFF", "POLL",
     56     0    stevel 	"POLLENTRY"};
     57     0    stevel char	inittracename[MAXPATHLEN+1];
     58     0    stevel static boolean_t file_trace;	/* 1=tracing to file, not stdout */
     59     0    stevel 
     60     0    stevel static void tmsg(const char *, ...);
     61     0    stevel 
     62     0    stevel const char *
     63     0    stevel rip_strerror(int err)
     64     0    stevel {
     65     0    stevel 	const char *cp = strerror(err);
     66     0    stevel 	static char msgbuf[64];
     67     0    stevel 
     68     0    stevel 	if (cp == NULL) {
     69     0    stevel 		if (err == 0) {
     70     0    stevel 			cp = "success";
     71     0    stevel 		} else {
     72     0    stevel 			(void) snprintf(msgbuf, sizeof (msgbuf),
     73     0    stevel 			    "unknown error %d", err);
     74     0    stevel 			cp = msgbuf;
     75     0    stevel 		}
     76     0    stevel 	}
     77     0    stevel 	return (cp);
     78     0    stevel }
     79     0    stevel 
     80     0    stevel /* convert IP address to a string, but not into a single buffer */
     81     0    stevel char *
     82     0    stevel naddr_ntoa(in_addr_t a)
     83     0    stevel {
     84     0    stevel #define	NUM_BUFS 4
     85     0    stevel 	static int bufno;
     86     0    stevel 	static struct {
     87     0    stevel 	    char    str[INET_ADDRSTRLEN];	/* xxx.xxx.xxx.xxx\0 */
     88     0    stevel 	} bufs[NUM_BUFS];
     89     0    stevel 	char *s;
     90     0    stevel 	struct in_addr addr;
     91     0    stevel 
     92     0    stevel 	addr.s_addr = a;
     93     0    stevel 	s = strcpy(bufs[bufno].str, inet_ntoa(addr));
     94     0    stevel 	bufno = (bufno+1) % NUM_BUFS;
     95     0    stevel 	return (s);
     96     0    stevel #undef NUM_BUFS
     97     0    stevel }
     98     0    stevel 
     99     0    stevel 
    100     0    stevel const char *
    101     0    stevel saddr_ntoa(struct sockaddr_storage *ss)
    102     0    stevel {
    103     0    stevel 	return (ss == NULL) ? "?" : naddr_ntoa(S_ADDR(ss));
    104     0    stevel }
    105     0    stevel 
    106     0    stevel 
    107     0    stevel static char *
    108     0    stevel ts(time_t secs)
    109     0    stevel {
    110     0    stevel 	static char s[20];
    111     0    stevel 
    112     0    stevel 	secs += epoch.tv_sec;
    113     0    stevel 	(void) strftime(s, sizeof (s), "%T", localtime(&secs));
    114     0    stevel 	return (s);
    115     0    stevel }
    116     0    stevel 
    117     0    stevel static char *
    118     0    stevel ts_full(struct timeval *tv)
    119     0    stevel {
    120     0    stevel 	static char s[32];
    121     0    stevel 	time_t secs;
    122     0    stevel 	int len;
    123     0    stevel 
    124     0    stevel 	secs = tv->tv_sec + epoch.tv_sec;
    125     0    stevel 	(void) strftime(s, sizeof (s), "%Y/%m/%d %T", localtime(&secs));
    126     0    stevel 	len = strlen(s);
    127     0    stevel 	(void) snprintf(s + len, sizeof (s) - len, ".%06ld", tv->tv_usec);
    128     0    stevel 	return (s);
    129     0    stevel }
    130     0    stevel 
    131     0    stevel /*
    132     0    stevel  * On each event, display a time stamp.
    133     0    stevel  * This assumes that 'now' is update once for each event, and
    134     0    stevel  * that at least now.tv_usec changes.
    135     0    stevel  */
    136     0    stevel static struct timeval lastlog_time;
    137     0    stevel 
    138     0    stevel void
    139     0    stevel lastlog(void)
    140     0    stevel {
    141     0    stevel 	if (lastlog_time.tv_sec != now.tv_sec ||
    142     0    stevel 	    lastlog_time.tv_usec != now.tv_usec) {
    143     0    stevel 		(void) fprintf(ftrace, "-- %s --\n", ts_full(&now));
    144     0    stevel 		lastlog_time = now;
    145     0    stevel 	}
    146     0    stevel }
    147     0    stevel 
    148     0    stevel 
    149     0    stevel static void
    150     0    stevel tmsg(const char *p, ...)
    151     0    stevel {
    152     0    stevel 	va_list args;
    153     0    stevel 
    154     0    stevel 	if (ftrace != NULL) {
    155     0    stevel 		lastlog();
    156     0    stevel 		va_start(args, p);
    157     0    stevel 		(void) vfprintf(ftrace, p, args);
    158     0    stevel 		(void) fputc('\n', ftrace);
    159     0    stevel 		(void) fflush(ftrace);
    160     0    stevel 		(void) va_end(args);
    161     0    stevel 	}
    162     0    stevel }
    163     0    stevel 
    164     0    stevel 
    165     0    stevel void
    166     0    stevel trace_close(int zap_stdio)
    167     0    stevel {
    168     0    stevel 	int fd;
    169     0    stevel 
    170     0    stevel 
    171     0    stevel 	(void) fflush(stdout);
    172     0    stevel 	(void) fflush(stderr);
    173     0    stevel 
    174     0    stevel 	if (ftrace != NULL && zap_stdio) {
    175     0    stevel 		if (ftrace != stdout)
    176     0    stevel 			(void) fclose(ftrace);
    177     0    stevel 		ftrace = NULL;
    178     0    stevel 		fd = open("/dev/null", O_RDWR);
    179     0    stevel 		if (isatty(STDIN_FILENO))
    180     0    stevel 			(void) dup2(fd, STDIN_FILENO);
    181     0    stevel 		if (isatty(STDOUT_FILENO))
    182     0    stevel 			(void) dup2(fd, STDOUT_FILENO);
    183     0    stevel 		if (isatty(STDERR_FILENO))
    184     0    stevel 			(void) dup2(fd, STDERR_FILENO);
    185     0    stevel 		(void) close(fd);
    186     0    stevel 	}
    187     0    stevel 	lastlog_time.tv_sec = 0;
    188     0    stevel }
    189     0    stevel 
    190     0    stevel 
    191     0    stevel void
    192     0    stevel trace_flush(void)
    193     0    stevel {
    194     0    stevel 	if (ftrace != NULL) {
    195     0    stevel 		(void) fflush(ftrace);
    196     0    stevel 		if (ferror(ftrace))
    197     0    stevel 			trace_off("tracing off: %s",
    198     0    stevel 			    rip_strerror(ferror(ftrace)));
    199     0    stevel 	}
    200     0    stevel }
    201     0    stevel 
    202     0    stevel 
    203     0    stevel void
    204     0    stevel trace_off(const char *p, ...)
    205     0    stevel {
    206     0    stevel 	va_list args;
    207     0    stevel 
    208     0    stevel 
    209     0    stevel 	if (ftrace != NULL) {
    210     0    stevel 		lastlog();
    211     0    stevel 		va_start(args, p);
    212     0    stevel 		(void) vfprintf(ftrace, p, args);
    213     0    stevel 		(void) fputc('\n', ftrace);
    214     0    stevel 		(void) va_end(args);
    215     0    stevel 	}
    216     0    stevel 	trace_close(file_trace);
    217     0    stevel 
    218     0    stevel 	new_tracelevel = tracelevel = 0;
    219     0    stevel }
    220     0    stevel 
    221     0    stevel 
    222     0    stevel /* log a change in tracing */
    223     0    stevel void
    224     0    stevel tracelevel_msg(const char *pat,
    225     0    stevel     int dump)		/* -1=no dump, 0=default, 1=force */
    226     0    stevel {
    227     0    stevel 	static const char *off_msgs[MAX_TRACELEVEL] = {
    228     0    stevel 		"Tracing actions stopped",
    229     0    stevel 		"Tracing packets stopped",
    230     0    stevel 		"Tracing packet contents stopped",
    231     0    stevel 		"Tracing kernel changes stopped",
    232     0    stevel 		"Tracing routing socket messages stopped",
    233     0    stevel 	};
    234     0    stevel 	static const char *on_msgs[MAX_TRACELEVEL] = {
    235     0    stevel 		"Tracing actions started",
    236     0    stevel 		"Tracing packets started",
    237     0    stevel 		"Tracing packet contents started",
    238     0    stevel 		"Tracing kernel changes started",
    239     0    stevel 		"Tracing routing socket messages started",
    240     0    stevel 	};
    241     0    stevel 	uint_t old_tracelevel = tracelevel;
    242     0    stevel 
    243     0    stevel 
    244     0    stevel 	if (new_tracelevel < 0)
    245     0    stevel 		new_tracelevel = 0;
    246     0    stevel 	else if (new_tracelevel > MAX_TRACELEVEL)
    247     0    stevel 		new_tracelevel = MAX_TRACELEVEL;
    248     0    stevel 
    249     0    stevel 	if (new_tracelevel < tracelevel) {
    250     0    stevel 		if (new_tracelevel <= 0) {
    251     0    stevel 			trace_off(pat, off_msgs[0]);
    252     0    stevel 		} else {
    253     0    stevel 			do {
    254     0    stevel 				tmsg(pat, off_msgs[tracelevel]);
    255     0    stevel 			} while (--tracelevel != new_tracelevel);
    256     0    stevel 		}
    257     0    stevel 
    258     0    stevel 	} else if (new_tracelevel > tracelevel) {
    259     0    stevel 		do {
    260     0    stevel 			tmsg(pat, on_msgs[tracelevel++]);
    261     0    stevel 		} while (tracelevel != new_tracelevel);
    262     0    stevel 	}
    263     0    stevel 
    264     0    stevel 	if (dump > 0 ||
    265     0    stevel 	    (dump == 0 && old_tracelevel == 0 && tracelevel != 0))
    266     0    stevel 		trace_dump();
    267     0    stevel }
    268     0    stevel 
    269     0    stevel void
    270     0    stevel set_tracefile(const char *filename,
    271     0    stevel     const char *pat,
    272     0    stevel     int dump)			/* -1=no dump, 0=default, 1=force */
    273     0    stevel {
    274     0    stevel 	struct stat stbuf;
    275     0    stevel 	struct stat stbuf2;
    276     0    stevel 	FILE *n_ftrace;
    277     0    stevel 	const char *fn;
    278     0    stevel 	int nfd;
    279     0    stevel 	boolean_t allow_create;
    280     0    stevel 
    281     0    stevel 	/*
    282     0    stevel 	 * main() calls this routine with "dump == -1".  All others
    283     0    stevel 	 * call it with 0, so we take dump == -1 to mean "can create
    284     0    stevel 	 * the file."
    285     0    stevel 	 */
    286     0    stevel 	allow_create = (dump == -1);
    287     0    stevel 
    288     0    stevel 	/*
    289     0    stevel 	 * Allow a null filename to increase the level if the trace file
    290     0    stevel 	 * is already open or if coming from a trusted source, such as
    291     0    stevel 	 * a signal or the command line.
    292     0    stevel 	 */
    293     0    stevel 	if (filename == NULL || filename[0] == '\0') {
    294     0    stevel 		filename = NULL;
    295     0    stevel 		if (ftrace == NULL) {
    296     0    stevel 			if (inittracename[0] == '\0') {
    297     0    stevel 				msglog("missing trace file name");
    298     0    stevel 				return;
    299     0    stevel 			}
    300     0    stevel 			fn = inittracename;
    301     0    stevel 		} else {
    302     0    stevel 			goto set_tracelevel;
    303     0    stevel 		}
    304     0    stevel 
    305     0    stevel 	} else if (strcmp(filename, "dump/../table") == 0) {
    306     0    stevel 		trace_dump();
    307     0    stevel 		return;
    308     0    stevel 
    309     0    stevel 	} else {
    310     0    stevel 		/*
    311     0    stevel 		 * Allow the file specified with "-T file" to be reopened,
    312     0    stevel 		 * but require all other names specified over the net to
    313     0    stevel 		 * match the official path.  The path can specify a directory
    314     0    stevel 		 * in which the file is to be created.
    315     0    stevel 		 */
    316     0    stevel 
    317     0    stevel 		if (strcmp(filename, inittracename) != 0) {
    318     0    stevel 			if (strncmp(filename, PATH_TRACE,
    319     0    stevel 			    sizeof (PATH_TRACE)-1) != 0 ||
    320     0    stevel 			    (strstr(filename, "../") != NULL)) {
    321     0    stevel 				msglog("wrong trace file \"%s\"", filename);
    322     0    stevel 				return;
    323     0    stevel 			}
    324     0    stevel 			if (stat(PATH_TRACE, &stbuf) == -1) {
    325     0    stevel 				fn = PATH_TRACE;
    326     0    stevel 				goto missing_file;
    327     0    stevel 			}
    328     0    stevel 			if (filename[sizeof (PATH_TRACE) - 1] != '\0' &&
    329     0    stevel 			    (filename[sizeof (PATH_TRACE) - 1] != '/' ||
    330     0    stevel 			    !S_ISDIR(stbuf.st_mode))) {
    331     0    stevel 				goto bad_file_type;
    332     0    stevel 			}
    333     0    stevel 			if (S_ISDIR(stbuf.st_mode))
    334     0    stevel 				allow_create = _B_TRUE;
    335     0    stevel 		}
    336     0    stevel 
    337     0    stevel 		fn = filename;
    338     0    stevel 	}
    339     0    stevel 	/* fn cannot be null here */
    340     0    stevel 
    341     0    stevel 	/* If the new tracefile exists, it must be a regular file. */
    342     0    stevel 	if (lstat(fn, &stbuf) == -1) {
    343     0    stevel 		if (!allow_create)
    344     0    stevel 			goto missing_file;
    345     0    stevel 		nfd = open(fn, O_CREAT|O_EXCL|O_WRONLY, 0644);
    346     0    stevel 		if (nfd != -1 && fstat(nfd, &stbuf) == -1) {
    347     0    stevel 			(void) close(nfd);
    348     0    stevel 			goto missing_file;
    349     0    stevel 		}
    350     0    stevel 	} else if (S_ISREG(stbuf.st_mode)) {
    351     0    stevel 		nfd = open(fn, O_APPEND|O_WRONLY, 0644);
    352     0    stevel 	} else {
    353     0    stevel 		goto bad_file_type;
    354     0    stevel 	}
    355     0    stevel 
    356     0    stevel 	if (nfd == -1 || (n_ftrace = fdopen(nfd, "a")) == NULL) {
    357     0    stevel 		msglog("failed to open trace file \"%s\" %s", fn,
    358     0    stevel 		    rip_strerror(errno));
    359     0    stevel 		if (fn == inittracename)
    360     0    stevel 			inittracename[0] = '\0';
    361     0    stevel 		if (nfd != -1)
    362     0    stevel 			(void) close(nfd);
    363     0    stevel 		return;
    364     0    stevel 	}
    365     0    stevel 
    366     0    stevel 	if (fstat(nfd, &stbuf2) == -1 || !S_ISREG(stbuf2.st_mode) ||
    367     0    stevel 	    stbuf2.st_dev != stbuf.st_dev || stbuf2.st_ino != stbuf.st_ino) {
    368     0    stevel 		msglog("trace file \"%s\" moved", fn);
    369     0    stevel 		(void) fclose(n_ftrace);
    370     0    stevel 		return;
    371     0    stevel 	}
    372     0    stevel 
    373     0    stevel 	tmsg("switch to trace file %s", fn);
    374     0    stevel 	trace_close(file_trace = _B_TRUE);
    375     0    stevel 	(void) dup2(nfd, STDOUT_FILENO);
    376     0    stevel 	(void) dup2(nfd, STDERR_FILENO);
    377     0    stevel 
    378     0    stevel 	if (fn != savetracename)
    379     0    stevel 		(void) strlcpy(savetracename, fn, sizeof (savetracename) - 1);
    380     0    stevel 	ftrace = n_ftrace;
    381     0    stevel 
    382     0    stevel set_tracelevel:
    383     0    stevel 	if (new_tracelevel == 0 || filename == NULL)
    384     0    stevel 		new_tracelevel++;
    385     0    stevel 	tracelevel_msg(pat, dump != 0 ? dump : (filename != NULL));
    386     0    stevel 	return;
    387     0    stevel 
    388     0    stevel missing_file:
    389     0    stevel 	msglog("trace \"%s\" missing", fn);
    390     0    stevel 	return;
    391     0    stevel 
    392     0    stevel bad_file_type:
    393     0    stevel 	msglog("wrong type (%#x) of trace file \"%s\"", stbuf.st_mode, fn);
    394     0    stevel }
    395     0    stevel 
    396     0    stevel 
    397     0    stevel /* ARGSUSED */
    398     0    stevel void
    399     0    stevel sigtrace_more(int s)
    400     0    stevel {
    401     0    stevel 	new_tracelevel++;
    402     0    stevel 	sigtrace_pat = "SIGUSR1: %s";
    403     0    stevel 	if (signal(s, sigtrace_more) == SIG_ERR)
    404     0    stevel 		msglog("signal: %s", rip_strerror(errno));
    405     0    stevel }
    406     0    stevel 
    407     0    stevel 
    408     0    stevel /* ARGSUSED */
    409     0    stevel void
    410     0    stevel sigtrace_less(int s)
    411     0    stevel {
    412     0    stevel 	new_tracelevel--;
    413     0    stevel 	sigtrace_pat = "SIGUSR2: %s";
    414     0    stevel 	if (signal(s, sigtrace_less) == SIG_ERR)
    415     0    stevel 		msglog("signal: %s", rip_strerror(errno));
    416     0    stevel }
    417     0    stevel 
    418     0    stevel /* ARGSUSED */
    419     0    stevel void
    420     0    stevel sigtrace_dump(int s)
    421     0    stevel {
    422     0    stevel 	trace_dump();
    423     0    stevel 	if (signal(s, sigtrace_dump) == SIG_ERR)
    424     0    stevel 		msglog("signal: %s", rip_strerror(errno));
    425     0    stevel }
    426     0    stevel 
    427     0    stevel /* Set tracing after a signal. */
    428     0    stevel void
    429     0    stevel set_tracelevel(void)
    430     0    stevel {
    431     0    stevel 	if (new_tracelevel == tracelevel)
    432     0    stevel 		return;
    433     0    stevel 
    434     0    stevel 	/*
    435     0    stevel 	 * If tracing entirely off, and there was no tracefile specified
    436     0    stevel 	 * on the command line, then leave it off.
    437     0    stevel 	 */
    438     0    stevel 	if (new_tracelevel > tracelevel && ftrace == NULL) {
    439     0    stevel 		if (savetracename[0] != '\0') {
    440     0    stevel 			set_tracefile(savetracename, sigtrace_pat, 0);
    441     0    stevel 		} else if (inittracename[0] != '\0') {
    442     0    stevel 			set_tracefile(inittracename, sigtrace_pat, 0);
    443     0    stevel 		} else {
    444     0    stevel 			new_tracelevel = 0;
    445     0    stevel 			return;
    446     0    stevel 		}
    447     0    stevel 	} else {
    448     0    stevel 		tracelevel_msg(sigtrace_pat, 0);
    449     0    stevel 	}
    450     0    stevel }
    451     0    stevel 
    452     0    stevel 
    453     0    stevel /* display an address */
    454     0    stevel char *
    455     0    stevel addrname(in_addr_t addr,	/* in network byte order */
    456     0    stevel     in_addr_t	mask,
    457     0    stevel     int	force)			/* 0=show mask if nonstandard, */
    458     0    stevel {					/*	1=always show mask, 2=never */
    459     0    stevel #define	NUM_BUFS 4
    460     0    stevel 	static int bufno;
    461     0    stevel 	static struct {
    462     0    stevel 	/*
    463     0    stevel 	 * this array can hold either of the following strings terminated
    464     0    stevel 	 * by a null character:
    465     0    stevel 	 * "xxx.xxx.xxx.xxx/xx"
    466     0    stevel 	 * "xxx.xxx.xxx.xxx (mask xxx.xxx.xxx.xxx)"
    467     0    stevel 	 *
    468     0    stevel 	 */
    469     0    stevel 	    char    str[2*INET_ADDRSTRLEN + sizeof (" (mask )")];
    470     0    stevel 	} bufs[NUM_BUFS];
    471     0    stevel 	char *s, *sp;
    472     0    stevel 	in_addr_t dmask;
    473     0    stevel 	int i, len;
    474     0    stevel 	struct in_addr tmp_addr;
    475     0    stevel 
    476     0    stevel 	tmp_addr.s_addr = addr;
    477     0    stevel 	len = strlcpy(bufs[bufno].str, inet_ntoa(tmp_addr),
    478     0    stevel 	    sizeof (bufs[bufno].str));
    479     0    stevel 	s = bufs[bufno].str;
    480     0    stevel 	bufno = (bufno+1) % NUM_BUFS;
    481     0    stevel 
    482     0    stevel 	if (force == 1 || (force == 0 && mask != std_mask(addr))) {
    483     0    stevel 		sp = &s[strlen(s)];
    484     0    stevel 
    485     0    stevel 		dmask = mask & -mask;
    486     0    stevel 		if (mask + dmask == 0) {
    487     0    stevel 			i = ffs(mask);
    488     0    stevel 			(void) snprintf(sp,
    489     0    stevel 			    (sizeof (bufs[bufno].str) - len), "/%d",
    490     0    stevel 			    (NBBY * sizeof (in_addr_t) + 1) - i);
    491     0    stevel 
    492     0    stevel 		} else {
    493     0    stevel 			(void) snprintf(sp,
    494     0    stevel 			    (sizeof (bufs[bufno].str) - len), " (mask %s)",
    495     0    stevel 			    naddr_ntoa(htonl(mask)));
    496     0    stevel 		}
    497     0    stevel 	}
    498     0    stevel 
    499     0    stevel 	return (s);
    500     0    stevel #undef NUM_BUFS
    501     0    stevel }
    502     0    stevel 
    503     0    stevel 
    504     0    stevel /* display a bit-field */
    505     0    stevel struct or_bits {
    506     0    stevel 	uint8_t	origin;
    507     0    stevel 	const char *origin_name;
    508     0    stevel };
    509     0    stevel 
    510     0    stevel static struct or_bits origin_bits[] = {
    511     0    stevel 	{ RO_RIP,		"RIP" },
    512     0    stevel 	{ RO_RDISC,		"RDISC" },
    513     0    stevel 	{ RO_STATIC,		"STATIC" },
    514     0    stevel 	{ RO_LOOPBCK,		"LOOPBCK" },
    515     0    stevel 	{ RO_PTOPT,		"PTOPT" },
    516     0    stevel 	{ RO_NET_SYN,		"NET_SYN" },
    517     0    stevel 	{ RO_IF,		"IF" },
    518     0    stevel 	{ RO_FILE,		"FILE" },
    519     0    stevel 	{ RO_NONE,		"     " },
    520     0    stevel 	{ 0,			NULL}
    521     0    stevel };
    522     0    stevel 
    523     0    stevel /* display a bit-field */
    524     0    stevel struct bits {
    525   192  carlsonj 	uint64_t	bits_mask;
    526   192  carlsonj 	uint64_t	bits_clear;
    527   192  carlsonj 	const char	*bits_name;
    528     0    stevel };
    529     0    stevel 
    530     0    stevel static struct bits if_bits[] = {
    531     0    stevel 	{ IFF_BROADCAST,	0,		"BROADCAST" },
    532     0    stevel 	{ IFF_DEBUG,		0,		"DEBUG" },
    533     0    stevel 	{ IFF_LOOPBACK,		0,		"LOOPBACK" },
    534     0    stevel 	{ IFF_POINTOPOINT,	0,		"POINTOPOINT" },
    535     0    stevel 	{ IFF_NOTRAILERS,	0,		"NOTRAILERS" },
    536     0    stevel 	{ IFF_RUNNING,		0,		"RUNNING" },
    537     0    stevel 	{ IFF_NOARP,		0,		"NOARP" },
    538     0    stevel 	{ IFF_PROMISC,		0,		"PROMISC" },
    539     0    stevel 	{ IFF_ALLMULTI,		0,		"ALLMULTI" },
    540     0    stevel 	{ IFF_INTELLIGENT,	0,		"INTELLIGENT" },
    541     0    stevel 	{ IFF_MULTICAST,	0,		"MULTICAST" },
    542     0    stevel 	{ IFF_MULTI_BCAST,	0,		"MULTI_BCAST" },
    543     0    stevel 	{ IFF_UNNUMBERED,	0,		"UNNUMBERED" },
    544     0    stevel 	{ IFF_DHCPRUNNING,	0,		"DHCP" },
    545     0    stevel 	{ IFF_PRIVATE,		0,		"PRIVATE" },
    546     0    stevel 	{ IFF_NOXMIT,		0,		"NOXMIT" },
    547     0    stevel 	{ IFF_NOLOCAL,		0,		"NOLOCAL" },
    548     0    stevel 	{ IFF_DEPRECATED,	0,		"DEPRECATED" },
    549     0    stevel 	{ IFF_ADDRCONF,		0,		"ADDRCONF" },
    550     0    stevel 	{ IFF_ROUTER,		0,		"ROUTER" },
    551     0    stevel 	{ IFF_NONUD,		0,		"NONUD" },
    552     0    stevel 	{ IFF_ANYCAST,		0,		"ANYCAST" },
    553     0    stevel 	{ IFF_NORTEXCH,		0,		"NORTEXCH" },
    554     0    stevel 	{ IFF_IPV4,		0,		"IPv4" },
    555     0    stevel 	{ IFF_IPV6,		0,		"IPv6" },
    556     0    stevel 	{ IFF_NOFAILOVER,	0,		"NOFAILOVER" },
    557     0    stevel 	{ IFF_FAILED,		0,		"FAILED" },
    558     0    stevel 	{ IFF_STANDBY,		0,		"STANDBY" },
    559     0    stevel 	{ IFF_INACTIVE,		0,		"INACTIVE" },
    560     0    stevel 	{ IFF_OFFLINE,		0,		"OFFLINE" },
    561     0    stevel 	{ IFF_XRESOLV,		0,		"XRESOLV" },
    562     0    stevel 	{ IFF_COS_ENABLED,	0,		"CoS" },
    563     0    stevel 	{ IFF_PREFERRED,	0,		"PREFERRED" },
    564     0    stevel 	{ IFF_TEMPORARY,	0,		"TEMPORARY" },
    565     0    stevel 	{ IFF_FIXEDMTU,		0,		"FIXEDMTU" },
    566     0    stevel 	{ IFF_VIRTUAL,		0,		"VIRTUAL"},
    567  8485     Peter 	{ IFF_IPMP,		0,		"IPMP"},
    568     0    stevel 	{ 0,			0,		NULL}
    569     0    stevel };
    570     0    stevel 
    571     0    stevel static struct bits is_bits[] = {
    572     0    stevel 	{ IS_ALIAS,		0,		"ALIAS" },
    573     0    stevel 	{ IS_SUBNET,		0,		"" },
    574     0    stevel 	{ IS_REMOTE,		(IS_NO_RDISC |
    575     0    stevel 				IS_BCAST_RDISC), "REMOTE" },
    576     0    stevel 	{ IS_PASSIVE,		(IS_NO_RDISC |
    577     0    stevel 				IS_NO_RIP |
    578     0    stevel 				IS_NO_SUPER_AG |
    579     0    stevel 				IS_PM_RDISC |
    580     0    stevel 				IS_NO_AG),	"PASSIVE" },
    581     0    stevel 	{ IS_EXTERNAL,		0,		"EXTERNAL" },
    582     0    stevel 	{ IS_CHECKED,		0,		"" },
    583     0    stevel 	{ IS_ALL_HOSTS,		0,		"" },
    584     0    stevel 	{ IS_ALL_ROUTERS,	0,		"" },
    585     0    stevel 	{ IS_DISTRUST,		0,		"DISTRUST" },
    586     0    stevel 	{ IS_BROKE,		IS_SICK,	"BROKEN" },
    587     0    stevel 	{ IS_SICK,		0,		"SICK" },
    588     0    stevel 	{ IS_DUP,		0,		"DUPLICATE" },
    589     0    stevel 	{ IS_REDIRECT_OK,	0,		"REDIRECT_OK" },
    590     0    stevel 	{ IS_NEED_NET_SYN,	0,		"" },
    591     0    stevel 	{ IS_NO_AG,		IS_NO_SUPER_AG,	"NO_AG" },
    592     0    stevel 	{ IS_NO_SUPER_AG,	0,		"NO_SUPER_AG" },
    593     0    stevel 	{ (IS_NO_RIPV1_IN |
    594     0    stevel 	    IS_NO_RIPV2_IN |
    595     0    stevel 	    IS_NO_RIPV1_OUT |
    596     0    stevel 	    IS_NO_RIPV2_OUT),	0,		"NO_RIP" },
    597     0    stevel 	{ (IS_NO_RIPV1_IN |
    598     0    stevel 	    IS_NO_RIPV1_OUT),	0,		"RIPV2" },
    599     0    stevel 	{ IS_NO_RIPV1_IN,	0,		"NO_RIPV1_IN" },
    600     0    stevel 	{ IS_NO_RIPV2_IN,	0,		"NO_RIPV2_IN" },
    601     0    stevel 	{ IS_NO_RIPV1_OUT,	0,		"NO_RIPV1_OUT" },
    602     0    stevel 	{ IS_NO_RIPV2_OUT,	0,		"NO_RIPV2_OUT" },
    603     0    stevel 	{ IS_NO_RIP_MCAST,	0,		"NO_RIP_MCAST" },
    604     0    stevel 	{ (IS_NO_ADV_IN |
    605     0    stevel 	    IS_NO_SOL_OUT |
    606     0    stevel 	    IS_NO_ADV_OUT),	IS_BCAST_RDISC,	"NO_RDISC" },
    607     0    stevel 	{ IS_NO_SOL_OUT,	0,		"NO_SOLICIT" },
    608     0    stevel 	{ IS_SOL_OUT,		0,		"SEND_SOLICIT" },
    609     0    stevel 	{ IS_NO_ADV_OUT,	IS_BCAST_RDISC,	"NO_RDISC_ADV" },
    610     0    stevel 	{ IS_ADV_OUT,		0,		"RDISC_ADV" },
    611     0    stevel 	{ IS_BCAST_RDISC,	0,		"BCAST_RDISC" },
    612     0    stevel 	{ IS_PM_RDISC,		0,		"" },
    613     0    stevel 	{ IS_NO_HOST,		0,		"NO_HOST" },
    614     0    stevel 	{ IS_SUPPRESS_RDISC,	0,		"SUPPRESS_RDISC" },
    615     0    stevel 	{ IS_FLUSH_RDISC,	0,		"FLUSH_RDISC" },
    616     0    stevel 	{ 0,			0,		NULL}
    617     0    stevel };
    618     0    stevel 
    619     0    stevel static struct bits rs_bits[] = {
    620     0    stevel 	{ RS_IF,		0,		"IF" },
    621     0    stevel 	{ RS_NET_INT,		RS_NET_SYN,	"NET_INT" },
    622     0    stevel 	{ RS_NET_SYN,		0,		"NET_SYN" },
    623     0    stevel 	{ RS_SUBNET,		0,		"" },
    624     0    stevel 	{ RS_LOCAL,		0,		"LOCAL" },
    625     0    stevel 	{ RS_MHOME,		0,		"MHOME" },
    626     0    stevel 	{ RS_STATIC,		0,		"STATIC" },
    627     0    stevel 	{ RS_NOPROPAGATE,	0,		"NOPROP" },
    628     0    stevel 	{ RS_BADIF,		0,		"BADIF" },
    629     0    stevel 	{ 0,			0,		NULL}
    630     0    stevel };
    631     0    stevel 
    632     0    stevel static struct bits ks_bits[] = {
    633     0    stevel 	{ KS_NEW,	0,		"NEW" },
    634     0    stevel 	{ KS_DELETE,	0,		"DELETE" },
    635     0    stevel 	{ KS_ADD,	0,		"ADD" },
    636     0    stevel 	{ KS_CHANGE,	0,		"CHANGE" },
    637     0    stevel 	{ KS_DEL_ADD,	0,		"DEL_ADD" },
    638     0    stevel 	{ KS_STATIC,	0,		"STATIC" },
    639     0    stevel 	{ KS_GATEWAY,	0,		"GATEWAY" },
    640     0    stevel 	{ KS_DYNAMIC,	0,		"DYNAMIC" },
    641     0    stevel 	{ KS_DELETED,	0,		"DELETED" },
    642     0    stevel 	{ KS_PRIVATE,	0,		"PRIVATE" },
    643     0    stevel 	{ KS_CHECK,	0,		"CHECK" },
    644     0    stevel 	{ KS_IF,	0,		"IF" },
    645     0    stevel 	{ KS_PASSIVE,	0,		"PASSIVE" },
    646     0    stevel 	{ KS_DEPRE_IF,	0,		"DEPRE_IF" },
    647     0    stevel 	{ KS_FILE,	0,		"FILE" },
    648     0    stevel 	{ 0,		0,		NULL}
    649     0    stevel };
    650     0    stevel 
    651     0    stevel static void
    652     0    stevel trace_bits(const struct bits *tbl,
    653   192  carlsonj     uint64_t field,
    654     0    stevel     boolean_t force)
    655     0    stevel {
    656   192  carlsonj 	uint64_t b;
    657     0    stevel 	char c;
    658     0    stevel 
    659     0    stevel 	if (force) {
    660     0    stevel 		(void) putc('<', ftrace);
    661     0    stevel 		c = '\0';
    662     0    stevel 	} else {
    663     0    stevel 		c = '<';
    664     0    stevel 	}
    665     0    stevel 
    666     0    stevel 	while (field != 0 &&
    667     0    stevel 	    (b = tbl->bits_mask) != 0) {
    668     0    stevel 		if ((b & field) == b) {
    669     0    stevel 			if (tbl->bits_name[0] != '\0') {
    670     0    stevel 				if (c != '\0')
    671     0    stevel 					(void) putc(c, ftrace);
    672     0    stevel 				(void) fprintf(ftrace, "%s", tbl->bits_name);
    673     0    stevel 				c = '|';
    674     0    stevel 			}
    675     0    stevel 			field &= ~(b | tbl->bits_clear);
    676     0    stevel 		}
    677     0    stevel 		tbl++;
    678     0    stevel 	}
    679     0    stevel 	if (field != 0) {
    680     0    stevel 		if (c != '\0')
    681     0    stevel 			(void) putc(c, ftrace);
    682   192  carlsonj 		(void) fprintf(ftrace, "%#llx", field);
    683     0    stevel 		c = '|';
    684     0    stevel 	}
    685     0    stevel 
    686     0    stevel 	if (c != '<' || force)
    687     0    stevel 		(void) fputs("> ", ftrace);
    688     0    stevel }
    689     0    stevel 
    690     0    stevel static char *
    691     0    stevel trace_string(const struct bits *tbl, uint_t field, boolean_t force)
    692     0    stevel {
    693     0    stevel 	const struct bits *tbp;
    694     0    stevel 	char *sbuf, *cp, chr;
    695     0    stevel 	size_t slen;
    696     0    stevel 
    697     0    stevel 	/* minimum default string */
    698     0    stevel 	slen = sizeof ("<0x12345678>");
    699     0    stevel 	for (tbp = tbl; tbp->bits_mask != 0; tbp++)
    700     0    stevel 		if (tbp->bits_name[0] != '\0')
    701     0    stevel 			slen += strlen(tbp->bits_name) + 1;
    702     0    stevel 	if ((sbuf = malloc(slen)) == NULL)
    703     0    stevel 		return (NULL);
    704     0    stevel 	cp = sbuf;
    705     0    stevel 
    706     0    stevel 	if (force) {
    707     0    stevel 		*cp++ = '<';
    708     0    stevel 		chr = '\0';
    709     0    stevel 	} else {
    710     0    stevel 		chr = '<';
    711     0    stevel 	}
    712     0    stevel 
    713     0    stevel 	while (field != 0 && tbl->bits_mask != 0) {
    714     0    stevel 		if ((tbl->bits_mask & field) == tbl->bits_mask) {
    715     0    stevel 			if (tbl->bits_name[0] != '\0') {
    716     0    stevel 				if (chr != '\0')
    717     0    stevel 					*cp++ = chr;
    718     0    stevel 				(void) strcpy(cp, tbl->bits_name);
    719     0    stevel 				cp += strlen(tbl->bits_name);
    720     0    stevel 				chr = '|';
    721     0    stevel 			}
    722     0    stevel 			field &= ~(tbl->bits_mask | tbl->bits_clear);
    723     0    stevel 		}
    724     0    stevel 		tbl++;
    725     0    stevel 	}
    726     0    stevel 	if (field != 0) {
    727     0    stevel 		if (chr != '\0')
    728     0    stevel 			*cp++ = chr;
    729     0    stevel 		cp += sprintf(cp, "%#x", field);
    730     0    stevel 		chr = '|';
    731     0    stevel 	}
    732     0    stevel 
    733     0    stevel 	if (chr != '<' || force)
    734     0    stevel 		*cp++ = '>';
    735     0    stevel 	*cp = '\0';
    736     0    stevel 	return (sbuf);
    737     0    stevel }
    738     0    stevel 
    739     0    stevel char *
    740     0    stevel if_bit_string(uint_t field, boolean_t force)
    741     0    stevel {
    742     0    stevel 	return (trace_string(if_bits, field, force));
    743     0    stevel }
    744     0    stevel 
    745     0    stevel char *
    746     0    stevel rtname(in_addr_t dst,
    747     0    stevel     in_addr_t mask,
    748     0    stevel     in_addr_t gate)
    749     0    stevel {
    750     0    stevel 	static char buf[sizeof ("xxx.xxx.xxx.xxx/xx-->xxx.xxx.xxx.xxx")];
    751     0    stevel 	int i;
    752     0    stevel 
    753     0    stevel 	(void) snprintf(buf, sizeof (buf), "%-16s-->", addrname(dst, mask, 0));
    754     0    stevel 	i = strlen(buf);
    755     0    stevel 	(void) snprintf(&buf[i], (sizeof (buf) -i), "%-*s", 15+24-MAX(24, i),
    756     0    stevel 	    naddr_ntoa(gate));
    757     0    stevel 	return (buf);
    758     0    stevel }
    759     0    stevel 
    760     0    stevel 
    761     0    stevel static void
    762     0    stevel print_rts(struct rt_spare *rts,
    763     0    stevel     int force_metric,		/* -1=suppress, 0=default */
    764     0    stevel     int force_ifp,		/* -1=suppress, 0=default */
    765     0    stevel     int force_router,		/* -1=suppress, 0=default, 1=display */
    766     0    stevel     int force_tag,		/* -1=suppress, 0=default, 1=display */
    767     0    stevel     int force_time)		/* 0=suppress, 1=display */
    768     0    stevel {
    769     0    stevel 	int i;
    770     0    stevel 
    771     0    stevel 	if (force_metric >= 0)
    772     0    stevel 		(void) fprintf(ftrace, "metric=%-2d ", rts->rts_metric);
    773     0    stevel 	if (force_ifp >= 0)
    774     0    stevel 		(void) fprintf(ftrace, "%s ", (rts->rts_ifp == 0 ?
    775     0    stevel 		    "if?" : rts->rts_ifp->int_name));
    776     0    stevel 	if (force_router > 0 ||
    777     0    stevel 	    (force_router == 0 && rts->rts_router != rts->rts_gate))
    778     0    stevel 		(void) fprintf(ftrace, "router=%s ",
    779     0    stevel 		    naddr_ntoa(rts->rts_router));
    780     0    stevel 	if (force_time > 0)
    781     0    stevel 		(void) fprintf(ftrace, "%s ", ts(rts->rts_time));
    782     0    stevel 	if (force_tag > 0 ||
    783     0    stevel 	    (force_tag == 0 && rts->rts_tag != 0))
    784     0    stevel 		(void) fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag));
    785     0    stevel 	if (rts->rts_de_ag != 0) {
    786     0    stevel 		for (i = 1; (uint_t)(1 << i) <= rts->rts_de_ag; i++)
    787     0    stevel 			continue;
    788     0    stevel 		(void) fprintf(ftrace, "de_ag=%d ", i);
    789     0    stevel 	}
    790     0    stevel 	(void) fprintf(ftrace, "flags 0x%x ", rts->rts_flags);
    791     0    stevel 
    792     0    stevel }
    793     0    stevel 
    794     0    stevel 
    795     0    stevel static void
    796     0    stevel print_rtsorigin(const struct or_bits *tbl, uint8_t route_origin)
    797     0    stevel {
    798     0    stevel 
    799     0    stevel 	uint8_t tblentry;
    800     0    stevel 	while ((tblentry = tbl->origin) != 0) {
    801     0    stevel 		if (tblentry == route_origin) {
    802     0    stevel 			(void) fprintf(ftrace, "origin=%s ", tbl->origin_name);
    803     0    stevel 		}
    804     0    stevel 		tbl++;
    805     0    stevel 	}
    806     0    stevel }
    807     0    stevel 
    808     0    stevel 
    809     0    stevel void
    810     0    stevel trace_if(const char *act, struct interface *ifp)
    811     0    stevel {
    812     0    stevel 	if (!TRACEACTIONS || ftrace == NULL)
    813     0    stevel 		return;
    814     0    stevel 
    815     0    stevel 	lastlog();
    816     0    stevel 	(void) fprintf(ftrace, "%-3s interface %-4s #%-3d ", act,
    817     0    stevel 	    ifp->int_name,
    818     0    stevel 	    ifp->int_phys != NULL ? ifp->int_phys->phyi_index : 0);
    819     0    stevel 	(void) fprintf(ftrace, "%-15s-->%-15s",
    820     0    stevel 	    naddr_ntoa(ifp->int_addr),
    821     0    stevel 	    addrname(((ifp->int_if_flags & IFF_POINTOPOINT) ?
    822     0    stevel 	    ifp->int_dstaddr : htonl(ifp->int_net)),
    823     0    stevel 	    ifp->int_mask, 1));
    824     0    stevel 	if (ifp->int_metric != 0)
    825     0    stevel 		(void) fprintf(ftrace, " metric=%d", ifp->int_metric);
    826     0    stevel 	if (!IS_RIP_OUT_OFF(ifp->int_state) &&
    827     0    stevel 	    ifp->int_d_metric != 0)
    828     0    stevel 		(void) fprintf(ftrace, " fake_default=%d", ifp->int_d_metric);
    829     0    stevel 	(void) fputs("\n    ", ftrace);
    830     0    stevel 	trace_bits(if_bits, ifp->int_if_flags, _B_FALSE);
    831     0    stevel 	trace_bits(is_bits, ifp->int_state, _B_FALSE);
    832     0    stevel 	(void) fputc('\n', ftrace);
    833     0    stevel }
    834     0    stevel 
    835     0    stevel void
    836     0    stevel trace_khash(const struct khash *krt)
    837     0    stevel {
    838     0    stevel 	if (ftrace == NULL)
    839     0    stevel 		return;
    840     0    stevel 
    841     0    stevel 	lastlog();
    842     0    stevel 	(void) fprintf(ftrace, "  %-15s-->%-15s metric=%d ",
    843     0    stevel 	    addrname(krt->k_dst, krt->k_mask, 0),
    844     0    stevel 	    naddr_ntoa(krt->k_gate), krt->k_metric);
    845     0    stevel 	if (krt->k_ifp != NULL)
    846     0    stevel 		(void) fprintf(ftrace, "ifp %s ", krt->k_ifp->int_name);
    847     0    stevel 	else
    848     0    stevel 		(void) fprintf(ftrace, "ifp NULL ");
    849     0    stevel 	(void) fprintf(ftrace, "%s ", ts(krt->k_keep));
    850     0    stevel 	(void) fprintf(ftrace, "%s ", ts(krt->k_redirect_time));
    851     0    stevel 	trace_bits(ks_bits, krt->k_state, _B_TRUE);
    852     0    stevel 	(void) fputc('\n', ftrace);
    853     0    stevel }
    854     0    stevel 
    855     0    stevel void
    856     0    stevel trace_dr(const struct dr *drp)
    857     0    stevel {
    858     0    stevel 	if (ftrace == NULL)
    859     0    stevel 		return;
    860     0    stevel 
    861     0    stevel 	lastlog();
    862     0    stevel 	(void) fprintf(ftrace, "  %-4s %-15s %s ",
    863     0    stevel 	    drp->dr_ifp != NULL ? drp->dr_ifp->int_name : "?",
    864     0    stevel 	    naddr_ntoa(drp->dr_gate), ts(drp->dr_ts));
    865     0    stevel 	(void) fprintf(ftrace, "%s %d %u\n", ts(drp->dr_life),
    866     0    stevel 	    SIGN_PREF(drp->dr_recv_pref), drp->dr_pref);
    867     0    stevel }
    868     0    stevel 
    869     0    stevel void
    870     0    stevel trace_upslot(struct rt_entry *rt,
    871     0    stevel     struct rt_spare *rts,
    872     0    stevel     struct rt_spare *new)
    873     0    stevel {
    874     0    stevel 	if (!TRACEACTIONS || ftrace == NULL)
    875     0    stevel 		return;
    876     0    stevel 
    877     0    stevel 	if (rts->rts_gate == new->rts_gate &&
    878     0    stevel 	    rts->rts_router == new->rts_router &&
    879     0    stevel 	    rts->rts_metric == new->rts_metric &&
    880     0    stevel 	    rts->rts_tag == new->rts_tag &&
    881     0    stevel 	    rts->rts_de_ag == new->rts_de_ag)
    882     0    stevel 		return;
    883     0    stevel 
    884     0    stevel 	lastlog();
    885     0    stevel 	if (new->rts_gate == 0) {
    886     0    stevel 		(void) fprintf(ftrace, "Del #%d %-35s ",
    887     0    stevel 		    (int)(rts - rt->rt_spares),
    888     0    stevel 		    rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate));
    889     0    stevel 		print_rts(rts, 0, 0, 0, 0,
    890     0    stevel 		    (rts != rt->rt_spares ||
    891     0    stevel 		    AGE_RT(rt->rt_state, rts->rts_origin, new->rts_ifp)));
    892     0    stevel 
    893     0    stevel 	} else if (rts->rts_gate != RIP_DEFAULT) {
    894     0    stevel 		(void) fprintf(ftrace, "Chg #%d %-35s ",
    895     0    stevel 		    (int)(rts - rt->rt_spares),
    896     0    stevel 		    rtname(rt->rt_dst, rt->rt_mask, rts->rts_gate));
    897     0    stevel 		print_rts(rts, 0, 0,
    898     0    stevel 		    rts->rts_gate != new->rts_gate,
    899     0    stevel 		    rts->rts_tag != new->rts_tag,
    900  8485     Peter 		    rts != rt->rt_spares ||
    901  8485     Peter 		    AGE_RT(rt->rt_state, rts->rts_origin, rt->rt_ifp));
    902     0    stevel 
    903     0    stevel 		(void) fprintf(ftrace, "\n       %19s%-16s ", "",
    904     0    stevel 		    (new->rts_gate != rts->rts_gate ?
    905     0    stevel 		    naddr_ntoa(new->rts_gate) : ""));
    906     0    stevel 		print_rts(new,
    907     0    stevel 		    ((new->rts_metric == rts->rts_metric) ? -1 : 0),
    908     0    stevel 		    ((new->rts_ifp == rts->rts_ifp) ? -1 : 0),
    909     0    stevel 		    0,
    910     0    stevel 		    rts->rts_tag != new->rts_tag,
    911     0    stevel 		    (new->rts_time != rts->rts_time &&
    912     0    stevel 		    (rts != rt->rt_spares ||
    913     0    stevel 		    AGE_RT(rt->rt_state, new->rts_origin, new->rts_ifp))));
    914     0    stevel 
    915     0    stevel 	} else {
    916     0    stevel 		(void) fprintf(ftrace, "Add #%d %-35s ",
    917     0    stevel 		    (int)(rts - rt->rt_spares),
    918     0    stevel 		    rtname(rt->rt_dst, rt->rt_mask, new->rts_gate));
    919     0    stevel 		print_rts(new, 0, 0, 0, 0,
    920     0    stevel 		    (rts != rt->rt_spares ||
    921     0    stevel 		    AGE_RT(rt->rt_state, new->rts_origin, new->rts_ifp)));
    922     0    stevel 	}
    923     0    stevel 	(void) fputc('\n', ftrace);
    924     0    stevel }
    925     0    stevel 
    926     0    stevel 
    927     0    stevel /* miscellaneous message checked by the caller */
    928     0    stevel void
    929     0    stevel trace_misc(const char *p, ...)
    930     0    stevel {
    931     0    stevel 	va_list args;
    932     0    stevel 
    933     0    stevel 	if (ftrace == NULL)
    934     0    stevel 		return;
    935     0    stevel 
    936     0    stevel 	lastlog();
    937     0    stevel 	va_start(args, p);
    938     0    stevel 	(void) vfprintf(ftrace, p, args);
    939     0    stevel 	(void) fputc('\n', ftrace);
    940     0    stevel 	(void) va_end(args);
    941     0    stevel }
    942     0    stevel 
    943     0    stevel 
    944     0    stevel /* display a message if tracing actions */
    945     0    stevel void
    946     0    stevel trace_act(const char *p, ...)
    947     0    stevel {
    948     0    stevel 	va_list args;
    949     0    stevel 
    950     0    stevel 	if (!TRACEACTIONS || ftrace == NULL)
    951     0    stevel 		return;
    952     0    stevel 
    953     0    stevel 	lastlog();
    954     0    stevel 	va_start(args, p);
    955     0    stevel 	(void) vfprintf(ftrace, p, args);
    956     0    stevel 	(void) fputc('\n', ftrace);
    957     0    stevel 	(void) va_end(args);
    958     0    stevel }
    959     0    stevel 
    960     0    stevel 
    961     0    stevel /* display a message if tracing packets */
    962     0    stevel void
    963     0    stevel trace_pkt(const char *p, ...)
    964     0    stevel {
    965     0    stevel 	va_list args;
    966     0    stevel 
    967     0    stevel 	if (!TRACEPACKETS || ftrace == NULL)
    968     0    stevel 		return;
    969     0    stevel 
    970     0    stevel 	lastlog();
    971     0    stevel 	va_start(args, p);
    972     0    stevel 	(void) vfprintf(ftrace, p, args);
    973     0    stevel 	(void) fputc('\n', ftrace);
    974     0    stevel 	(void) va_end(args);
    975     0    stevel }
    976     0    stevel 
    977     0    stevel 
    978     0    stevel void
    979     0    stevel trace_change(struct rt_entry *rt,
    980     0    stevel     uint16_t	state,
    981     0    stevel     struct	rt_spare *new,
    982     0    stevel     const char	*label)
    983     0    stevel {
    984     0    stevel 	if (ftrace == NULL)
    985     0    stevel 		return;
    986     0    stevel 
    987     0    stevel 	if (rt->rt_metric == new->rts_metric &&
    988     0    stevel 	    rt->rt_gate == new->rts_gate &&
    989     0    stevel 	    rt->rt_router == new->rts_router &&
    990     0    stevel 	    rt->rt_state == state &&
    991     0    stevel 	    rt->rt_tag == new->rts_tag &&
    992     0    stevel 	    rt->rt_de_ag == new->rts_de_ag)
    993     0    stevel 		return;
    994     0    stevel 
    995     0    stevel 	lastlog();
    996     0    stevel 	(void) fprintf(ftrace, "%s %-35s ",
    997     0    stevel 	    label,
    998     0    stevel 	    rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate));
    999     0    stevel 	print_rts(rt->rt_spares,
   1000     0    stevel 	    0, 0, 0, 0, AGE_RT(rt->rt_state, rt->rt_spares->rts_origin,
   1001     0    stevel 	    rt->rt_ifp));
   1002     0    stevel 	print_rtsorigin(origin_bits, rt->rt_spares->rts_origin);
   1003     0    stevel 	trace_bits(rs_bits, rt->rt_state, rt->rt_state != state);
   1004     0    stevel 
   1005     0    stevel 	(void) fprintf(ftrace, "\n%*s %19s%-16s ",
   1006     0    stevel 	    strlen(label), "", "",
   1007     0    stevel 	    (rt->rt_gate != new->rts_gate ?
   1008     0    stevel 	    naddr_ntoa(new->rts_gate) : ""));
   1009     0    stevel 	print_rts(new,
   1010     0    stevel 	    ((new->rts_metric == rt->rt_metric) ? -1 : 0),
   1011     0    stevel 	    ((new->rts_ifp == rt->rt_ifp) ? -1 : 0),
   1012     0    stevel 	    0,
   1013     0    stevel 	    rt->rt_tag != new->rts_tag,
   1014     0    stevel 	    (rt->rt_time != new->rts_time &&
   1015     0    stevel 	    AGE_RT(rt->rt_state, new->rts_origin, new->rts_ifp)));
   1016     0    stevel 	if (rt->rt_state != state) {
   1017     0    stevel 		print_rtsorigin(origin_bits, new->rts_origin);
   1018     0    stevel 		trace_bits(rs_bits, state, _B_TRUE);
   1019     0    stevel 	}
   1020     0    stevel 	(void) fputc('\n', ftrace);
   1021     0    stevel }
   1022     0    stevel 
   1023     0    stevel 
   1024     0    stevel void
   1025     0    stevel trace_add_del(const char *action, struct rt_entry *rt)
   1026     0    stevel {
   1027     0    stevel 	if (ftrace == NULL)
   1028     0    stevel 		return;
   1029     0    stevel 
   1030     0    stevel 	lastlog();
   1031     0    stevel 	(void) fprintf(ftrace, "%s    %-35s ",
   1032     0    stevel 	    action,
   1033     0    stevel 	    rtname(rt->rt_dst, rt->rt_mask, rt->rt_gate));
   1034     0    stevel 	print_rts(rt->rt_spares, 0, 0, 0, 0, AGE_RT(rt->rt_state,
   1035     0    stevel 	    rt->rt_spares->rts_origin, rt->rt_ifp));
   1036     0    stevel 	print_rtsorigin(origin_bits, rt->rt_spares->rts_origin);
   1037     0    stevel 	trace_bits(rs_bits, rt->rt_state, _B_FALSE);
   1038     0    stevel 	(void) fputc('\n', ftrace);
   1039     0    stevel }
   1040     0    stevel 
   1041     0    stevel 
   1042     0    stevel /* ARGSUSED */
   1043     0    stevel static int
   1044     0    stevel walk_trace(struct radix_node *rn,
   1045     0    stevel     void *w)
   1046     0    stevel {
   1047     0    stevel #define	RT ((struct rt_entry *)rn)
   1048     0    stevel 	struct rt_spare *rts;
   1049     0    stevel 	int i;
   1050     0    stevel 
   1051     0    stevel 	(void) fprintf(ftrace, "  %-35s ",
   1052     0    stevel 	    rtname(RT->rt_dst, RT->rt_mask, RT->rt_gate));
   1053     0    stevel 	print_rts(&RT->rt_spares[0], 0, 0, 0, 0,
   1054     0    stevel 	    AGE_RT(RT->rt_state, RT->rt_spares[0].rts_origin, RT->rt_ifp));
   1055     0    stevel 	print_rtsorigin(origin_bits, RT->rt_spares[0].rts_origin);
   1056     0    stevel 	trace_bits(rs_bits, RT->rt_state, _B_FALSE);
   1057     0    stevel 	if (RT->rt_poison_time >= now_garbage &&
   1058     0    stevel 	    RT->rt_poison_metric < RT->rt_metric)
   1059     0    stevel 		(void) fprintf(ftrace, "pm=%d@%s",
   1060     0    stevel 		    RT->rt_poison_metric, ts(RT->rt_poison_time));
   1061   552   sowmini 	(void) fprintf(ftrace, "%d spare slots", RT->rt_num_spares);
   1062     0    stevel 
   1063     0    stevel 	rts = &RT->rt_spares[1];
   1064     0    stevel 	for (i = 1; i < RT->rt_num_spares; i++, rts++) {
   1065     0    stevel 		if (rts->rts_gate != RIP_DEFAULT) {
   1066     0    stevel 			(void) fprintf(ftrace, "\n    #%d%15s%-16s ",
   1067     0    stevel 			    i, "", naddr_ntoa(rts->rts_gate));
   1068     0    stevel 			print_rts(rts, 0, 0, 0, 0, 1);
   1069     0    stevel 			print_rtsorigin(origin_bits, rts->rts_origin);
   1070     0    stevel 		}
   1071     0    stevel 	}
   1072     0    stevel 	(void) fputc('\n', ftrace);
   1073     0    stevel 
   1074     0    stevel 	return (0);
   1075     0    stevel }
   1076     0    stevel 
   1077     0    stevel 
   1078     0    stevel void
   1079     0    stevel trace_dump(void)
   1080     0    stevel {
   1081     0    stevel 	struct interface *ifp;
   1082     0    stevel 
   1083     0    stevel 	if (ftrace == NULL)
   1084     0    stevel 		return;
   1085     0    stevel 	lastlog();
   1086     0    stevel 
   1087     0    stevel 	/*
   1088     0    stevel 	 * Warning: the rtquery.trace.* family of STC tests depend on
   1089     0    stevel 	 * the log file format here.  If you need to change this next
   1090     0    stevel 	 * message, make sure that you change the TRACE_DUMP variable
   1091     0    stevel 	 * as well.
   1092     0    stevel 	 */
   1093     0    stevel 	(void) fputs("current daemon state:\n", ftrace);
   1094     0    stevel 	for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next)
   1095     0    stevel 		trace_if("", ifp);
   1096     0    stevel 	(void) fputs("Routes:\n", ftrace);
   1097     0    stevel 	(void) rn_walktree(rhead, walk_trace, NULL);
   1098     0    stevel 	(void) fputs("Kernel routes:\n", ftrace);
   1099     0    stevel 	kern_dump();
   1100     0    stevel 	(void) fputs("Discovered routers:\n", ftrace);
   1101     0    stevel 	rdisc_dump();
   1102     0    stevel }
   1103     0    stevel 
   1104     0    stevel 
   1105     0    stevel void
   1106     0    stevel trace_rip(const char *dir1, const char *dir2,
   1107     0    stevel     struct sockaddr_in *who,
   1108     0    stevel     struct interface *ifp,
   1109     0    stevel     struct rip *msg,
   1110     0    stevel     int size)			/* total size of message */
   1111     0    stevel {
   1112     0    stevel 	struct netinfo *n, *lim;
   1113     0    stevel #define	NA ((struct netauth *)n)
   1114     0    stevel 	int i, seen_route;
   1115     0    stevel 	struct in_addr tmp_mask;
   1116     0    stevel 
   1117     0    stevel 	if (!TRACEPACKETS || ftrace == NULL)
   1118     0    stevel 		return;
   1119     0    stevel 
   1120     0    stevel 	lastlog();
   1121     0    stevel 	if (msg->rip_cmd >= RIPCMD_MAX || msg->rip_vers == 0) {
   1122     0    stevel 		(void) fprintf(ftrace, "%s bad RIPv%d cmd=%d %s"
   1123     0    stevel 		    " %s.%d size=%d\n",
   1124     0    stevel 		    dir1, msg->rip_vers, msg->rip_cmd, dir2,
   1125     0    stevel 		    naddr_ntoa(who->sin_addr.s_addr),
   1126     0    stevel 		    ntohs(who->sin_port),
   1127     0    stevel 		    size);
   1128     0    stevel 		return;
   1129     0    stevel 	}
   1130     0    stevel 
   1131     0    stevel 	(void) fprintf(ftrace, "%s RIPv%d %s %s %s.%d%s%s\n",
   1132     0    stevel 	    dir1, msg->rip_vers, ripcmds[msg->rip_cmd], dir2,
   1133     0    stevel 	    naddr_ntoa(who->sin_addr.s_addr), ntohs(who->sin_port),
   1134     0    stevel 	    ifp ? " via " : "", ifp ? ifp->int_name : "");
   1135     0    stevel 	if (!TRACECONTENTS)
   1136     0    stevel 		return;
   1137     0    stevel 
   1138     0    stevel 	seen_route = 0;
   1139     0    stevel 	switch (msg->rip_cmd) {
   1140     0    stevel 	case RIPCMD_REQUEST:
   1141     0    stevel 	case RIPCMD_RESPONSE:
   1142     0    stevel 
   1143     0    stevel 		n = msg->rip_nets;
   1144     0    stevel 		tmp_mask.s_addr = n->n_mask;
   1145     0    stevel 		lim = n + (size - 4) / sizeof (struct netinfo);
   1146     0    stevel 		for (; n < lim; n++) {
   1147     0    stevel 			if (!seen_route &&
   1148     0    stevel 			    n->n_family == RIP_AF_UNSPEC &&
   1149     0    stevel 			    ntohl(n->n_metric) == HOPCNT_INFINITY &&
   1150     0    stevel 			    msg->rip_cmd == RIPCMD_REQUEST &&
   1151     0    stevel 			    (n+1 == lim ||
   1152     0    stevel 			    (n+2 == lim &&
   1153     0    stevel 			    (n+1)->n_family == RIP_AF_AUTH))) {
   1154     0    stevel 				(void) fputs("\tQUERY ", ftrace);
   1155     0    stevel 				if (n->n_dst != 0)
   1156     0    stevel 					(void) fprintf(ftrace, "%s ",
   1157     0    stevel 					    naddr_ntoa(n->n_dst));
   1158     0    stevel 				if (n->n_mask != 0)
   1159     0    stevel 					(void) fprintf(ftrace, "mask=%s ",
   1160     0    stevel 					    inet_ntoa(tmp_mask));
   1161     0    stevel 				if (n->n_nhop != 0)
   1162     0    stevel 					(void) fprintf(ftrace, "nhop=%s ",
   1163     0    stevel 					    naddr_ntoa(n->n_nhop));
   1164     0    stevel 				if (n->n_tag != 0)
   1165     0    stevel 					(void) fprintf(ftrace, "tag=%#x ",
   1166     0    stevel 					    ntohs(n->n_tag));
   1167     0    stevel 				(void) fputc('\n', ftrace);
   1168     0    stevel 				continue;
   1169     0    stevel 			}
   1170     0    stevel 
   1171     0    stevel 			if (n->n_family == RIP_AF_AUTH) {
   1172     0    stevel 				if (NA->a_type == RIP_AUTH_PW &&
   1173     0    stevel 				    n == msg->rip_nets) {
   1174     0    stevel 					(void) fprintf(ftrace, "\tPassword"
   1175  8485     Peter 					    " Authentication: \"%s\"\n",
   1176     0    stevel 					    qstring(NA->au.au_pw,
   1177  8485     Peter 					    RIP_AUTH_PW_LEN));
   1178     0    stevel 					continue;
   1179     0    stevel 				}
   1180     0    stevel 
   1181     0    stevel 				if (NA->a_type == RIP_AUTH_MD5 &&
   1182     0    stevel 				    n == msg->rip_nets) {
   1183     0    stevel 					(void) fprintf(ftrace,
   1184     0    stevel 					    "\tMD5 Auth"
   1185     0    stevel 					    " pkt_len=%d KeyID=%u"
   1186     0    stevel 					    " auth_len=%d"
   1187  8485     Peter 					    " seqno=%#x"
   1188  8485     Peter 					    " rsvd=%#hx,%#hx\n",
   1189     0    stevel 					    ntohs(NA->au.a_md5.md5_pkt_len),
   1190     0    stevel 					    NA->au.a_md5.md5_keyid,
   1191     0    stevel 					    NA->au.a_md5.md5_auth_len,
   1192  8485     Peter 					    ntohl(NA->au.a_md5.md5_seqno),
   1193     0    stevel 					    ntohs(NA->au.a_md5.rsvd[0]),
   1194     0    stevel 					    ntohs(NA->au.a_md5.rsvd[1]));
   1195     0    stevel 					continue;
   1196     0    stevel 				}
   1197     0    stevel 				(void) fprintf(ftrace,
   1198     0    stevel 				    "\tAuthentication type %d: ",
   1199     0    stevel 				    ntohs(NA->a_type));
   1200     0    stevel 				for (i = 0; i < (int)sizeof (NA->au.au_pw);
   1201     0    stevel 				    i++)
   1202     0    stevel 					(void) fprintf(ftrace, "%02x ",
   1203     0    stevel 					    NA->au.au_pw[i]);
   1204     0    stevel 				(void) fputc('\n', ftrace);
   1205     0    stevel 				continue;
   1206     0    stevel 			}
   1207     0    stevel 
   1208     0    stevel 			seen_route = 1;
   1209     0    stevel 			if (n->n_family != RIP_AF_INET) {
   1210     0    stevel 				(void) fprintf(ftrace,
   1211     0    stevel 				    "\t(af %d) %-18s mask=%s ",
   1212     0    stevel 				    ntohs(n->n_family),
   1213     0    stevel 				    naddr_ntoa(n->n_dst),
   1214     0    stevel 				    inet_ntoa(tmp_mask));
   1215     0    stevel 			} else if (msg->rip_vers == RIPv1) {
   1216     0    stevel 				(void) fprintf(ftrace, "\t%-18s ",
   1217  8485     Peter 				    addrname(n->n_dst, ntohl(n->n_mask),
   1218  8485     Peter 				    n->n_mask == 0 ? 2 : 1));
   1219     0    stevel 			} else {
   1220     0    stevel 				(void) fprintf(ftrace, "\t%-18s ",
   1221  8485     Peter 				    addrname(n->n_dst, ntohl(n->n_mask),
   1222  8485     Peter 				    n->n_mask == 0 ? 2 : 0));
   1223     0    stevel 			}
   1224     0    stevel 			(void) fprintf(ftrace, "metric=%-2lu ",
   1225     0    stevel 			    (unsigned long)ntohl(n->n_metric));
   1226     0    stevel 			if (n->n_nhop != 0)
   1227     0    stevel 				(void) fprintf(ftrace, " nhop=%s ",
   1228     0    stevel 				    naddr_ntoa(n->n_nhop));
   1229     0    stevel 			if (n->n_tag != 0)
   1230     0    stevel 				(void) fprintf(ftrace, "tag=%#x",
   1231     0    stevel 				    ntohs(n->n_tag));
   1232     0    stevel 			(void) fputc('\n', ftrace);
   1233     0    stevel 		}
   1234     0    stevel 		if (size != (char *)n - (char *)msg)
   1235     0    stevel 			(void) fprintf(ftrace, "truncated record, len %d\n",
   1236     0    stevel 			    size);
   1237     0    stevel 		break;
   1238     0    stevel 
   1239     0    stevel 	case RIPCMD_TRACEON:
   1240  8485     Peter 		(void) fprintf(ftrace, "\tfile=\"%.*s\"\n", size - 4,
   1241  8485     Peter 		    msg->rip_tracefile);
   1242     0    stevel 		break;
   1243     0    stevel 
   1244     0    stevel 	case RIPCMD_TRACEOFF:
   1245     0    stevel 		break;
   1246     0    stevel 	}
   1247     0    stevel }
   1248