xref: /freebsd/sbin/routed/trace.c (revision d5b718b3ee1a3d309b44921e01bba0ca4511ff00)
17b6ab19dSGarrett Wollman /*
27b6ab19dSGarrett Wollman  * Copyright (c) 1983, 1988, 1993
37b6ab19dSGarrett Wollman  *	The Regents of the University of California.  All rights reserved.
47b6ab19dSGarrett Wollman  *
57b6ab19dSGarrett Wollman  * Redistribution and use in source and binary forms, with or without
67b6ab19dSGarrett Wollman  * modification, are permitted provided that the following conditions
77b6ab19dSGarrett Wollman  * are met:
87b6ab19dSGarrett Wollman  * 1. Redistributions of source code must retain the above copyright
97b6ab19dSGarrett Wollman  *    notice, this list of conditions and the following disclaimer.
107b6ab19dSGarrett Wollman  * 2. Redistributions in binary form must reproduce the above copyright
117b6ab19dSGarrett Wollman  *    notice, this list of conditions and the following disclaimer in the
127b6ab19dSGarrett Wollman  *    documentation and/or other materials provided with the distribution.
137b6ab19dSGarrett Wollman  * 3. All advertising materials mentioning features or use of this software
147b6ab19dSGarrett Wollman  *    must display the following acknowledgement:
157b6ab19dSGarrett Wollman  *	This product includes software developed by the University of
167b6ab19dSGarrett Wollman  *	California, Berkeley and its contributors.
177b6ab19dSGarrett Wollman  * 4. Neither the name of the University nor the names of its contributors
187b6ab19dSGarrett Wollman  *    may be used to endorse or promote products derived from this software
197b6ab19dSGarrett Wollman  *    without specific prior written permission.
207b6ab19dSGarrett Wollman  *
217b6ab19dSGarrett Wollman  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
227b6ab19dSGarrett Wollman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
237b6ab19dSGarrett Wollman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
247b6ab19dSGarrett Wollman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
257b6ab19dSGarrett Wollman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
267b6ab19dSGarrett Wollman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
277b6ab19dSGarrett Wollman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
287b6ab19dSGarrett Wollman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
297b6ab19dSGarrett Wollman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
307b6ab19dSGarrett Wollman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
317b6ab19dSGarrett Wollman  * SUCH DAMAGE.
327b6ab19dSGarrett Wollman  */
337b6ab19dSGarrett Wollman 
347b6ab19dSGarrett Wollman #if !defined(lint) && !defined(sgi) && !defined(__NetBSD__)
357b6ab19dSGarrett Wollman static char sccsid[] = "@(#)trace.c	8.1 (Berkeley) 6/5/93";
367b6ab19dSGarrett Wollman #elif defined(__NetBSD__)
377b6ab19dSGarrett Wollman static char rcsid[] = "$NetBSD$";
387b6ab19dSGarrett Wollman #endif
39d5b718b3SGarrett Wollman #ident "$Revision: 1.14 $"
407b6ab19dSGarrett Wollman 
417b6ab19dSGarrett Wollman #define	RIPCMDS
427b6ab19dSGarrett Wollman #include "defs.h"
437b6ab19dSGarrett Wollman #include "pathnames.h"
447b6ab19dSGarrett Wollman #include <sys/stat.h>
457b6ab19dSGarrett Wollman #include <sys/signal.h>
467b6ab19dSGarrett Wollman #include <fcntl.h>
477b6ab19dSGarrett Wollman 
487b6ab19dSGarrett Wollman 
497b6ab19dSGarrett Wollman #ifdef sgi
507b6ab19dSGarrett Wollman /* use *stat64 for files on large filesystems */
517b6ab19dSGarrett Wollman #define stat	stat64
527b6ab19dSGarrett Wollman #endif
537b6ab19dSGarrett Wollman 
547b6ab19dSGarrett Wollman #define	NRECORDS	50		/* size of circular trace buffer */
557b6ab19dSGarrett Wollman 
567b6ab19dSGarrett Wollman u_int	tracelevel, new_tracelevel;
577b6ab19dSGarrett Wollman FILE	*ftrace = stdout;		/* output trace file */
587b6ab19dSGarrett Wollman static char *tracelevel_pat = "%s\n";
597b6ab19dSGarrett Wollman 
607b6ab19dSGarrett Wollman char savetracename[MAXPATHLEN+1];
617b6ab19dSGarrett Wollman 
627b6ab19dSGarrett Wollman static void trace_dump(void);
637b6ab19dSGarrett Wollman 
647b6ab19dSGarrett Wollman 
65d5b718b3SGarrett Wollman /* convert string to printable characters
66d5b718b3SGarrett Wollman  */
67d5b718b3SGarrett Wollman static char *
68d5b718b3SGarrett Wollman qstring(u_char *s, int len)
69d5b718b3SGarrett Wollman {
70d5b718b3SGarrett Wollman 	static char buf[8*20+1];
71d5b718b3SGarrett Wollman 	char *p;
72d5b718b3SGarrett Wollman 	u_char *s2, c;
73d5b718b3SGarrett Wollman 
74d5b718b3SGarrett Wollman 
75d5b718b3SGarrett Wollman 	for (p = buf; len != 0 && p < &buf[sizeof(buf)-1]; len--) {
76d5b718b3SGarrett Wollman 		c = *s++;
77d5b718b3SGarrett Wollman 		if (c == '\0') {
78d5b718b3SGarrett Wollman 			for (s2 = s+1; s2 < &s[len]; s2++) {
79d5b718b3SGarrett Wollman 				if (*s2 != '\0')
80d5b718b3SGarrett Wollman 					break;
81d5b718b3SGarrett Wollman 			}
82d5b718b3SGarrett Wollman 			if (s2 >= &s[len])
83d5b718b3SGarrett Wollman 			    goto exit;
84d5b718b3SGarrett Wollman 		}
85d5b718b3SGarrett Wollman 
86d5b718b3SGarrett Wollman 		if (c >= ' ' && c < 0x7f && c != '\\') {
87d5b718b3SGarrett Wollman 			*p++ = c;
88d5b718b3SGarrett Wollman 			continue;
89d5b718b3SGarrett Wollman 		}
90d5b718b3SGarrett Wollman 		*p++ = '\\';
91d5b718b3SGarrett Wollman 		switch (c) {
92d5b718b3SGarrett Wollman 		case '\\':
93d5b718b3SGarrett Wollman 			*p++ = '\\';
94d5b718b3SGarrett Wollman 			break;
95d5b718b3SGarrett Wollman 		case '\n':
96d5b718b3SGarrett Wollman 			*p++= 'n';
97d5b718b3SGarrett Wollman 			break;
98d5b718b3SGarrett Wollman 		case '\r':
99d5b718b3SGarrett Wollman 			*p++= 'r';
100d5b718b3SGarrett Wollman 			break;
101d5b718b3SGarrett Wollman 		case '\t':
102d5b718b3SGarrett Wollman 			*p++ = 't';
103d5b718b3SGarrett Wollman 			break;
104d5b718b3SGarrett Wollman 		case '\b':
105d5b718b3SGarrett Wollman 			*p++ = 'b';
106d5b718b3SGarrett Wollman 			break;
107d5b718b3SGarrett Wollman 		default:
108d5b718b3SGarrett Wollman 			p += sprintf(p,"%o",c);
109d5b718b3SGarrett Wollman 			break;
110d5b718b3SGarrett Wollman 		}
111d5b718b3SGarrett Wollman 	}
112d5b718b3SGarrett Wollman exit:
113d5b718b3SGarrett Wollman 	*p = '\0';
114d5b718b3SGarrett Wollman 	return buf;
115d5b718b3SGarrett Wollman }
116d5b718b3SGarrett Wollman 
117d5b718b3SGarrett Wollman 
1187b6ab19dSGarrett Wollman /* convert IP address to a string, but not into a single buffer
1197b6ab19dSGarrett Wollman  */
1207b6ab19dSGarrett Wollman char *
1217b6ab19dSGarrett Wollman naddr_ntoa(naddr a)
1227b6ab19dSGarrett Wollman {
1237b6ab19dSGarrett Wollman #define NUM_BUFS 4
1247b6ab19dSGarrett Wollman 	static int bufno;
1257b6ab19dSGarrett Wollman 	static struct {
1267b6ab19dSGarrett Wollman 	    char    str[16];		/* xxx.xxx.xxx.xxx\0 */
1277b6ab19dSGarrett Wollman 	} bufs[NUM_BUFS];
1287b6ab19dSGarrett Wollman 	char *s;
1297b6ab19dSGarrett Wollman 	struct in_addr addr;
1307b6ab19dSGarrett Wollman 
1317b6ab19dSGarrett Wollman 	addr.s_addr = a;
1327b6ab19dSGarrett Wollman 	s = strcpy(bufs[bufno].str, inet_ntoa(addr));
1337b6ab19dSGarrett Wollman 	bufno = (bufno+1) % NUM_BUFS;
1347b6ab19dSGarrett Wollman 	return s;
1357b6ab19dSGarrett Wollman #undef NUM_BUFS
1367b6ab19dSGarrett Wollman }
1377b6ab19dSGarrett Wollman 
1387b6ab19dSGarrett Wollman 
1397b6ab19dSGarrett Wollman char *
1407b6ab19dSGarrett Wollman saddr_ntoa(struct sockaddr *sa)
1417b6ab19dSGarrett Wollman {
1427b6ab19dSGarrett Wollman 	return (sa == 0) ? "?" : naddr_ntoa(S_ADDR(sa));
1437b6ab19dSGarrett Wollman }
1447b6ab19dSGarrett Wollman 
1457b6ab19dSGarrett Wollman 
1467b6ab19dSGarrett Wollman static char *
1477b6ab19dSGarrett Wollman ts(time_t secs) {
1487b6ab19dSGarrett Wollman 	static char s[20];
1497b6ab19dSGarrett Wollman 
1507b6ab19dSGarrett Wollman 	secs += epoch.tv_sec;
1517b6ab19dSGarrett Wollman #ifdef sgi
1527b6ab19dSGarrett Wollman 	(void)cftime(s, "%T", &secs);
1537b6ab19dSGarrett Wollman #else
1547b6ab19dSGarrett Wollman 	bcopy(ctime(&secs)+11, s, 8);
1557b6ab19dSGarrett Wollman 	s[8] = '\0';
1567b6ab19dSGarrett Wollman #endif
1577b6ab19dSGarrett Wollman 	return s;
1587b6ab19dSGarrett Wollman }
1597b6ab19dSGarrett Wollman 
1607b6ab19dSGarrett Wollman 
1617b6ab19dSGarrett Wollman /* On each event, display a time stamp.
1627b6ab19dSGarrett Wollman  * This assumes that 'now' is update once for each event, and
1637b6ab19dSGarrett Wollman  * that at least now.tv_usec changes.
1647b6ab19dSGarrett Wollman  */
1657b6ab19dSGarrett Wollman void
1667b6ab19dSGarrett Wollman lastlog(void)
1677b6ab19dSGarrett Wollman {
1687b6ab19dSGarrett Wollman 	static struct timeval last;
1697b6ab19dSGarrett Wollman 
1707b6ab19dSGarrett Wollman 	if (last.tv_sec != now.tv_sec
1717b6ab19dSGarrett Wollman 	    || last.tv_usec != now.tv_usec) {
1727b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "-- %s --\n", ts(now.tv_sec));
1737b6ab19dSGarrett Wollman 		last = now;
1747b6ab19dSGarrett Wollman 	}
1757b6ab19dSGarrett Wollman }
1767b6ab19dSGarrett Wollman 
1777b6ab19dSGarrett Wollman 
1787b6ab19dSGarrett Wollman static void
1797b6ab19dSGarrett Wollman tmsg(char *p, ...)
1807b6ab19dSGarrett Wollman {
1817b6ab19dSGarrett Wollman 	va_list args;
1827b6ab19dSGarrett Wollman 
1837b6ab19dSGarrett Wollman 	if (ftrace != 0) {
1847b6ab19dSGarrett Wollman 		lastlog();
1857b6ab19dSGarrett Wollman 		va_start(args, p);
1867b6ab19dSGarrett Wollman 		vfprintf(ftrace, p, args);
1877b6ab19dSGarrett Wollman 		fflush(ftrace);
1887b6ab19dSGarrett Wollman 	}
1897b6ab19dSGarrett Wollman }
1907b6ab19dSGarrett Wollman 
1917b6ab19dSGarrett Wollman 
1927b6ab19dSGarrett Wollman static void
1937b6ab19dSGarrett Wollman trace_close(void)
1947b6ab19dSGarrett Wollman {
1957b6ab19dSGarrett Wollman 	int fd;
1967b6ab19dSGarrett Wollman 
1977b6ab19dSGarrett Wollman 
1987b6ab19dSGarrett Wollman 	fflush(stdout);
1997b6ab19dSGarrett Wollman 	fflush(stderr);
2007b6ab19dSGarrett Wollman 
2017b6ab19dSGarrett Wollman 	if (ftrace != 0
2027b6ab19dSGarrett Wollman 	    && savetracename[0] != '\0') {
2037b6ab19dSGarrett Wollman 		fd = open(_PATH_DEVNULL, O_RDWR);
2047b6ab19dSGarrett Wollman 		(void)dup2(fd, STDOUT_FILENO);
2057b6ab19dSGarrett Wollman 		(void)dup2(fd, STDERR_FILENO);
2067b6ab19dSGarrett Wollman 		(void)close(fd);
2077b6ab19dSGarrett Wollman 		fclose(ftrace);
2087b6ab19dSGarrett Wollman 		ftrace = 0;
2097b6ab19dSGarrett Wollman 	}
2107b6ab19dSGarrett Wollman }
2117b6ab19dSGarrett Wollman 
2127b6ab19dSGarrett Wollman 
2137b6ab19dSGarrett Wollman void
2147b6ab19dSGarrett Wollman trace_flush(void)
2157b6ab19dSGarrett Wollman {
2167b6ab19dSGarrett Wollman 	if (ftrace != 0) {
2177b6ab19dSGarrett Wollman 		fflush(ftrace);
2187b6ab19dSGarrett Wollman 		if (ferror(ftrace))
2197b6ab19dSGarrett Wollman 			trace_off("tracing off: ", strerror(ferror(ftrace)));
2207b6ab19dSGarrett Wollman 	}
2217b6ab19dSGarrett Wollman }
2227b6ab19dSGarrett Wollman 
2237b6ab19dSGarrett Wollman 
2247b6ab19dSGarrett Wollman void
2257b6ab19dSGarrett Wollman trace_off(char *p, ...)
2267b6ab19dSGarrett Wollman {
2277b6ab19dSGarrett Wollman 	va_list args;
2287b6ab19dSGarrett Wollman 
2297b6ab19dSGarrett Wollman 
2307b6ab19dSGarrett Wollman 	if (ftrace != 0) {
2317b6ab19dSGarrett Wollman 		lastlog();
2327b6ab19dSGarrett Wollman 		va_start(args, p);
2337b6ab19dSGarrett Wollman 		vfprintf(ftrace, p, args);
2347b6ab19dSGarrett Wollman 		fflush(ftrace);
2357b6ab19dSGarrett Wollman 	}
2367b6ab19dSGarrett Wollman 	trace_close();
2377b6ab19dSGarrett Wollman 
2387b6ab19dSGarrett Wollman 	new_tracelevel = tracelevel = 0;
2397b6ab19dSGarrett Wollman }
2407b6ab19dSGarrett Wollman 
2417b6ab19dSGarrett Wollman 
2427b6ab19dSGarrett Wollman void
2437b6ab19dSGarrett Wollman trace_on(char *filename,
244d5b718b3SGarrett Wollman 	 int initial)			/* 1=setting from command line */
2457b6ab19dSGarrett Wollman {
2467b6ab19dSGarrett Wollman 	struct stat stbuf;
2477b6ab19dSGarrett Wollman 	FILE *n_ftrace;
248d5b718b3SGarrett Wollman 	u_int old_tracelevel;
2497b6ab19dSGarrett Wollman 
2507b6ab19dSGarrett Wollman 
2517b6ab19dSGarrett Wollman 	/* Given a null filename when tracing is already on, increase the
2527b6ab19dSGarrett Wollman 	 * debugging level and re-open the file in case it has been unlinked.
2537b6ab19dSGarrett Wollman 	 */
2547b6ab19dSGarrett Wollman 	if (filename[0] == '\0') {
2557b6ab19dSGarrett Wollman 		if (tracelevel != 0) {
2567b6ab19dSGarrett Wollman 			new_tracelevel++;
2577b6ab19dSGarrett Wollman 			tracelevel_pat = "trace command: %s\n";
2587b6ab19dSGarrett Wollman 		} else if (savetracename[0] == '\0') {
2597b6ab19dSGarrett Wollman 			msglog("missing trace file name");
2607b6ab19dSGarrett Wollman 			return;
2617b6ab19dSGarrett Wollman 		}
2627b6ab19dSGarrett Wollman 		filename = savetracename;
2637b6ab19dSGarrett Wollman 
2647b6ab19dSGarrett Wollman 	} else if (!strcmp(filename,"dump/../table")) {
2657b6ab19dSGarrett Wollman 		trace_dump();
2667b6ab19dSGarrett Wollman 		return;
2677b6ab19dSGarrett Wollman 
2687b6ab19dSGarrett Wollman 	} else {
2697b6ab19dSGarrett Wollman 		if (stat(filename, &stbuf) >= 0
2707b6ab19dSGarrett Wollman 		    && (stbuf.st_mode & S_IFMT) != S_IFREG) {
2717b6ab19dSGarrett Wollman 			msglog("wrong type (%#x) of trace file \"%s\"",
2727b6ab19dSGarrett Wollman 			       stbuf.st_mode, filename);
2737b6ab19dSGarrett Wollman 			return;
2747b6ab19dSGarrett Wollman 		}
2757b6ab19dSGarrett Wollman 
276d5b718b3SGarrett Wollman 		if (!initial
2777b6ab19dSGarrett Wollman #ifdef _PATH_TRACE
2787b6ab19dSGarrett Wollman 		    && (strncmp(filename, _PATH_TRACE, sizeof(_PATH_TRACE)-1)
2797b6ab19dSGarrett Wollman 			|| strstr(filename,"../")
2807b6ab19dSGarrett Wollman 			|| 0 > stat(_PATH_TRACE, &stbuf))
2817b6ab19dSGarrett Wollman #endif
2827b6ab19dSGarrett Wollman 		    && strcmp(filename, savetracename)) {
2837b6ab19dSGarrett Wollman 			msglog("wrong directory for trace file \"%s\"",
2847b6ab19dSGarrett Wollman 			       filename);
2857b6ab19dSGarrett Wollman 			return;
2867b6ab19dSGarrett Wollman 		}
2877b6ab19dSGarrett Wollman 	}
2887b6ab19dSGarrett Wollman 
2897b6ab19dSGarrett Wollman 	n_ftrace = fopen(filename, "a");
2907b6ab19dSGarrett Wollman 	if (n_ftrace == 0) {
2917b6ab19dSGarrett Wollman 		msglog("failed to open trace file \"%s\" %s",
2927b6ab19dSGarrett Wollman 		       filename, strerror(errno));
2937b6ab19dSGarrett Wollman 		return;
2947b6ab19dSGarrett Wollman 	}
2957b6ab19dSGarrett Wollman 
2967b6ab19dSGarrett Wollman 	tmsg("switch to trace file %s\n", filename);
2977b6ab19dSGarrett Wollman 	trace_close();
2987b6ab19dSGarrett Wollman 	if (filename != savetracename)
2997b6ab19dSGarrett Wollman 		strncpy(savetracename, filename, sizeof(savetracename)-1);
3007b6ab19dSGarrett Wollman 	ftrace = n_ftrace;
3017b6ab19dSGarrett Wollman 
3027b6ab19dSGarrett Wollman 	fflush(stdout);
3037b6ab19dSGarrett Wollman 	fflush(stderr);
3047b6ab19dSGarrett Wollman 	dup2(fileno(ftrace), STDOUT_FILENO);
3057b6ab19dSGarrett Wollman 	dup2(fileno(ftrace), STDERR_FILENO);
3067b6ab19dSGarrett Wollman 
3077b6ab19dSGarrett Wollman 	if (new_tracelevel == 0)
3087b6ab19dSGarrett Wollman 		new_tracelevel = 1;
309d5b718b3SGarrett Wollman 	old_tracelevel = tracelevel;
310d5b718b3SGarrett Wollman 	set_tracelevel(initial);
311d5b718b3SGarrett Wollman 
312d5b718b3SGarrett Wollman 	if (!initial && old_tracelevel == 0)
313d5b718b3SGarrett Wollman 		trace_dump();
3147b6ab19dSGarrett Wollman }
3157b6ab19dSGarrett Wollman 
3167b6ab19dSGarrett Wollman 
3177b6ab19dSGarrett Wollman /* ARGSUSED */
3187b6ab19dSGarrett Wollman void
3197b6ab19dSGarrett Wollman sigtrace_on(int s)
3207b6ab19dSGarrett Wollman {
3217b6ab19dSGarrett Wollman 	new_tracelevel++;
3227b6ab19dSGarrett Wollman 	tracelevel_pat = "SIGUSR1: %s\n";
3237b6ab19dSGarrett Wollman }
3247b6ab19dSGarrett Wollman 
3257b6ab19dSGarrett Wollman 
3267b6ab19dSGarrett Wollman /* ARGSUSED */
3277b6ab19dSGarrett Wollman void
3287b6ab19dSGarrett Wollman sigtrace_off(int s)
3297b6ab19dSGarrett Wollman {
3307b6ab19dSGarrett Wollman 	new_tracelevel--;
3317b6ab19dSGarrett Wollman 	tracelevel_pat = "SIGUSR2: %s\n";
3327b6ab19dSGarrett Wollman }
3337b6ab19dSGarrett Wollman 
3347b6ab19dSGarrett Wollman 
3357b6ab19dSGarrett Wollman /* Move to next higher level of tracing when -t option processed or
3367b6ab19dSGarrett Wollman  * SIGUSR1 is received.  Successive levels are:
3377b6ab19dSGarrett Wollman  *	actions
3387b6ab19dSGarrett Wollman  *	actions + packets
3397b6ab19dSGarrett Wollman  *	actions + packets + contents
3407b6ab19dSGarrett Wollman  */
3417b6ab19dSGarrett Wollman void
342d5b718b3SGarrett Wollman set_tracelevel(int initial)
3437b6ab19dSGarrett Wollman {
3447b6ab19dSGarrett Wollman 	static char *off_msgs[MAX_TRACELEVEL] = {
3457b6ab19dSGarrett Wollman 		"Tracing actions stopped",
3467b6ab19dSGarrett Wollman 		"Tracing packets stopped",
3477b6ab19dSGarrett Wollman 		"Tracing packet contents stopped",
3487b6ab19dSGarrett Wollman 		"Tracing kernel changes stopped",
3497b6ab19dSGarrett Wollman 	};
3507b6ab19dSGarrett Wollman 	static char *on_msgs[MAX_TRACELEVEL] = {
3517b6ab19dSGarrett Wollman 		"Tracing actions started",
3527b6ab19dSGarrett Wollman 		"Tracing packets started",
3537b6ab19dSGarrett Wollman 		"Tracing packet contents started",
3547b6ab19dSGarrett Wollman 		"Tracing kernel changes started",
3557b6ab19dSGarrett Wollman 	};
3567b6ab19dSGarrett Wollman 
3577b6ab19dSGarrett Wollman 
3587b6ab19dSGarrett Wollman 	if (new_tracelevel > MAX_TRACELEVEL) {
3597b6ab19dSGarrett Wollman 		new_tracelevel = MAX_TRACELEVEL;
3607b6ab19dSGarrett Wollman 		if (new_tracelevel == tracelevel) {
3617b6ab19dSGarrett Wollman 			tmsg(tracelevel_pat, on_msgs[tracelevel-1]);
3627b6ab19dSGarrett Wollman 			return;
3637b6ab19dSGarrett Wollman 		}
3647b6ab19dSGarrett Wollman 	}
365d5b718b3SGarrett Wollman 
366d5b718b3SGarrett Wollman 	for (; new_tracelevel != tracelevel; tracelevel++) {
3677b6ab19dSGarrett Wollman 		if (new_tracelevel < tracelevel) {
3687b6ab19dSGarrett Wollman 			if (--tracelevel == 0)
3697b6ab19dSGarrett Wollman 				trace_off(tracelevel_pat, off_msgs[0]);
3707b6ab19dSGarrett Wollman 			else
3717b6ab19dSGarrett Wollman 				tmsg(tracelevel_pat, off_msgs[tracelevel]);
3727b6ab19dSGarrett Wollman 		} else {
3737b6ab19dSGarrett Wollman 			if (ftrace == 0) {
3747b6ab19dSGarrett Wollman 				if (savetracename[0] != '\0')
3757b6ab19dSGarrett Wollman 					trace_on(savetracename, 1);
3767b6ab19dSGarrett Wollman 				else
3777b6ab19dSGarrett Wollman 					ftrace = stdout;
3787b6ab19dSGarrett Wollman 			}
379d5b718b3SGarrett Wollman 			if (!initial || tracelevel+1 == new_tracelevel)
380d5b718b3SGarrett Wollman 				tmsg(tracelevel_pat, on_msgs[tracelevel]);
3817b6ab19dSGarrett Wollman 		}
3827b6ab19dSGarrett Wollman 	}
3837b6ab19dSGarrett Wollman 	tracelevel_pat = "%s\n";
3847b6ab19dSGarrett Wollman }
3857b6ab19dSGarrett Wollman 
3867b6ab19dSGarrett Wollman 
3877b6ab19dSGarrett Wollman /* display an address
3887b6ab19dSGarrett Wollman  */
3897b6ab19dSGarrett Wollman char *
3907b6ab19dSGarrett Wollman addrname(naddr	addr,			/* in network byte order */
3917b6ab19dSGarrett Wollman 	 naddr	mask,
3927b6ab19dSGarrett Wollman 	 int	force)			/* 0=show mask if nonstandard, */
3937b6ab19dSGarrett Wollman {					/*	1=always show mask, 2=never */
3947b6ab19dSGarrett Wollman #define NUM_BUFS 4
3957b6ab19dSGarrett Wollman 	static int bufno;
3967b6ab19dSGarrett Wollman 	static struct {
3977b6ab19dSGarrett Wollman 	    char    str[15+20];
3987b6ab19dSGarrett Wollman 	} bufs[NUM_BUFS];
3997b6ab19dSGarrett Wollman 	char *s, *sp;
4007b6ab19dSGarrett Wollman 	naddr dmask;
4017b6ab19dSGarrett Wollman 	int i;
4027b6ab19dSGarrett Wollman 
4037b6ab19dSGarrett Wollman 	s = strcpy(bufs[bufno].str, naddr_ntoa(addr));
4047b6ab19dSGarrett Wollman 	bufno = (bufno+1) % NUM_BUFS;
4057b6ab19dSGarrett Wollman 
4067b6ab19dSGarrett Wollman 	if (force == 1 || (force == 0 && mask != std_mask(addr))) {
4077b6ab19dSGarrett Wollman 		sp = &s[strlen(s)];
4087b6ab19dSGarrett Wollman 
4097b6ab19dSGarrett Wollman 		dmask = mask & -mask;
4107b6ab19dSGarrett Wollman 		if (mask + dmask == 0) {
4117b6ab19dSGarrett Wollman 			for (i = 0; i != 32 && ((1<<i) & mask) == 0; i++)
4127b6ab19dSGarrett Wollman 				continue;
4137b6ab19dSGarrett Wollman 			(void)sprintf(sp, "/%d", 32-i);
4147b6ab19dSGarrett Wollman 
4157b6ab19dSGarrett Wollman 		} else {
4167b6ab19dSGarrett Wollman 			(void)sprintf(sp, " (mask %#x)", (u_int)mask);
4177b6ab19dSGarrett Wollman 		}
4187b6ab19dSGarrett Wollman 	}
4197b6ab19dSGarrett Wollman 
4207b6ab19dSGarrett Wollman 	return s;
4217b6ab19dSGarrett Wollman #undef NUM_BUFS
4227b6ab19dSGarrett Wollman }
4237b6ab19dSGarrett Wollman 
4247b6ab19dSGarrett Wollman 
4257b6ab19dSGarrett Wollman /* display a bit-field
4267b6ab19dSGarrett Wollman  */
4277b6ab19dSGarrett Wollman struct bits {
4287b6ab19dSGarrett Wollman 	int	bits_mask;
4297b6ab19dSGarrett Wollman 	int	bits_clear;
4307b6ab19dSGarrett Wollman 	char	*bits_name;
4317b6ab19dSGarrett Wollman };
4327b6ab19dSGarrett Wollman 
4337b6ab19dSGarrett Wollman static struct bits if_bits[] = {
4347b6ab19dSGarrett Wollman 	{ IFF_LOOPBACK,		0,		"LOOPBACK" },
4357b6ab19dSGarrett Wollman 	{ IFF_POINTOPOINT,	0,		"PT-TO-PT" },
4367b6ab19dSGarrett Wollman 	{ 0,			0,		0}
4377b6ab19dSGarrett Wollman };
4387b6ab19dSGarrett Wollman 
4397b6ab19dSGarrett Wollman static struct bits is_bits[] = {
440d5b718b3SGarrett Wollman 	{ IS_ALIAS,		0,		"ALIAS" },
4417b6ab19dSGarrett Wollman 	{ IS_SUBNET,		0,		"" },
442d5b718b3SGarrett Wollman 	{ IS_REMOTE,		(IS_NO_RDISC
443d5b718b3SGarrett Wollman 				 | IS_BCAST_RDISC), "REMOTE" },
4447b6ab19dSGarrett Wollman 	{ IS_PASSIVE,		(IS_NO_RDISC
4457b6ab19dSGarrett Wollman 				 | IS_NO_RIP
4467b6ab19dSGarrett Wollman 				 | IS_NO_SUPER_AG
4477b6ab19dSGarrett Wollman 				 | IS_PM_RDISC
4487b6ab19dSGarrett Wollman 				 | IS_NO_AG),	"PASSIVE" },
4497b6ab19dSGarrett Wollman 	{ IS_EXTERNAL,		0,		"EXTERNAL" },
4507b6ab19dSGarrett Wollman 	{ IS_CHECKED,		0,		"" },
4517b6ab19dSGarrett Wollman 	{ IS_ALL_HOSTS,		0,		"" },
4527b6ab19dSGarrett Wollman 	{ IS_ALL_ROUTERS,	0,		"" },
453d5b718b3SGarrett Wollman 	{ IS_DISTRUST,		0,		"DISTRUST" },
4547b6ab19dSGarrett Wollman 	{ IS_BROKE,		IS_SICK,	"BROKEN" },
4557b6ab19dSGarrett Wollman 	{ IS_SICK,		0,		"SICK" },
456d5b718b3SGarrett Wollman 	{ IS_DUP,		0,		"DUPLICATE" },
4577b6ab19dSGarrett Wollman 	{ IS_NEED_NET_SYN,	0,		"" },
4587b6ab19dSGarrett Wollman 	{ IS_NO_AG,		IS_NO_SUPER_AG,	"NO_AG" },
4597b6ab19dSGarrett Wollman 	{ IS_NO_SUPER_AG,	0,		"NO_SUPER_AG" },
4607b6ab19dSGarrett Wollman 	{ (IS_NO_RIPV1_IN
4617b6ab19dSGarrett Wollman 	   | IS_NO_RIPV2_IN
4627b6ab19dSGarrett Wollman 	   | IS_NO_RIPV1_OUT
4637b6ab19dSGarrett Wollman 	   | IS_NO_RIPV2_OUT),	0,		"NO_RIP" },
4647b6ab19dSGarrett Wollman 	{ (IS_NO_RIPV1_IN
4657b6ab19dSGarrett Wollman 	   | IS_NO_RIPV1_OUT),	0,		"RIPV2" },
4667b6ab19dSGarrett Wollman 	{ IS_NO_RIPV1_IN,	0,		"NO_RIPV1_IN" },
4677b6ab19dSGarrett Wollman 	{ IS_NO_RIPV2_IN,	0,		"NO_RIPV2_IN" },
4687b6ab19dSGarrett Wollman 	{ IS_NO_RIPV1_OUT,	0,		"NO_RIPV1_OUT" },
4697b6ab19dSGarrett Wollman 	{ IS_NO_RIPV2_OUT,	0,		"NO_RIPV2_OUT" },
4707b6ab19dSGarrett Wollman 	{ (IS_NO_ADV_IN
4717b6ab19dSGarrett Wollman 	   | IS_NO_SOL_OUT
4727b6ab19dSGarrett Wollman 	   | IS_NO_ADV_OUT),	IS_BCAST_RDISC,	"NO_RDISC" },
4737b6ab19dSGarrett Wollman 	{ IS_NO_SOL_OUT,	0,		"NO_SOLICIT" },
4747b6ab19dSGarrett Wollman 	{ IS_SOL_OUT,		0,		"SEND_SOLICIT" },
4757b6ab19dSGarrett Wollman 	{ IS_NO_ADV_OUT,	IS_BCAST_RDISC,	"NO_RDISC_ADV" },
4767b6ab19dSGarrett Wollman 	{ IS_ADV_OUT,		0,		"RDISC_ADV" },
4777b6ab19dSGarrett Wollman 	{ IS_BCAST_RDISC,	0,		"BCAST_RDISC" },
478d5b718b3SGarrett Wollman 	{ IS_PM_RDISC,		0,		"" },
4797b6ab19dSGarrett Wollman 	{ 0,			0,		"%#x"}
4807b6ab19dSGarrett Wollman };
4817b6ab19dSGarrett Wollman 
4827b6ab19dSGarrett Wollman static struct bits rs_bits[] = {
4837b6ab19dSGarrett Wollman 	{ RS_IF,		0,		"IF" },
4847b6ab19dSGarrett Wollman 	{ RS_NET_INT,		RS_NET_SYN,	"NET_INT" },
4857b6ab19dSGarrett Wollman 	{ RS_NET_SYN,		0,		"NET_SYN" },
4867b6ab19dSGarrett Wollman 	{ RS_SUBNET,		0,		"" },
4877b6ab19dSGarrett Wollman 	{ RS_LOCAL,		0,		"LOCAL" },
4887b6ab19dSGarrett Wollman 	{ RS_MHOME,		0,		"MHOME" },
4897b6ab19dSGarrett Wollman 	{ RS_STATIC,		0,		"STATIC" },
4907b6ab19dSGarrett Wollman 	{ RS_RDISC,		0,		"RDISC" },
4917b6ab19dSGarrett Wollman 	{ 0,			0,		"%#x"}
4927b6ab19dSGarrett Wollman };
4937b6ab19dSGarrett Wollman 
4947b6ab19dSGarrett Wollman 
4957b6ab19dSGarrett Wollman static void
4967b6ab19dSGarrett Wollman trace_bits(struct bits *tbl,
4977b6ab19dSGarrett Wollman 	   u_int field,
4987b6ab19dSGarrett Wollman 	   int force)
4997b6ab19dSGarrett Wollman {
5007b6ab19dSGarrett Wollman 	int b;
5017b6ab19dSGarrett Wollman 	char c;
5027b6ab19dSGarrett Wollman 
5037b6ab19dSGarrett Wollman 	if (force) {
5047b6ab19dSGarrett Wollman 		(void)putc('<', ftrace);
5057b6ab19dSGarrett Wollman 		c = 0;
5067b6ab19dSGarrett Wollman 	} else {
5077b6ab19dSGarrett Wollman 		c = '<';
5087b6ab19dSGarrett Wollman 	}
5097b6ab19dSGarrett Wollman 
5107b6ab19dSGarrett Wollman 	while (field != 0
5117b6ab19dSGarrett Wollman 	       && (b = tbl->bits_mask) != 0) {
5127b6ab19dSGarrett Wollman 		if ((b & field) == b) {
5137b6ab19dSGarrett Wollman 			if (tbl->bits_name[0] != '\0') {
5147b6ab19dSGarrett Wollman 				if (c)
5157b6ab19dSGarrett Wollman 					(void)putc(c, ftrace);
5167b6ab19dSGarrett Wollman 				(void)fprintf(ftrace, "%s", tbl->bits_name);
5177b6ab19dSGarrett Wollman 				c = '|';
5187b6ab19dSGarrett Wollman 			}
5197b6ab19dSGarrett Wollman 			if (0 == (field &= ~(b | tbl->bits_clear)))
5207b6ab19dSGarrett Wollman 				break;
5217b6ab19dSGarrett Wollman 		}
5227b6ab19dSGarrett Wollman 		tbl++;
5237b6ab19dSGarrett Wollman 	}
5247b6ab19dSGarrett Wollman 	if (field != 0 && tbl->bits_name != 0) {
5257b6ab19dSGarrett Wollman 		if (c)
5267b6ab19dSGarrett Wollman 			(void)putc(c, ftrace);
5277b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, tbl->bits_name, field);
5287b6ab19dSGarrett Wollman 		c = '|';
5297b6ab19dSGarrett Wollman 	}
5307b6ab19dSGarrett Wollman 
5317b6ab19dSGarrett Wollman 	if (c != '<' || force)
5327b6ab19dSGarrett Wollman 		(void)fputs("> ", ftrace);
5337b6ab19dSGarrett Wollman }
5347b6ab19dSGarrett Wollman 
5357b6ab19dSGarrett Wollman 
5367b6ab19dSGarrett Wollman static char *
5377b6ab19dSGarrett Wollman trace_pair(naddr dst,
5387b6ab19dSGarrett Wollman 	   naddr mask,
5397b6ab19dSGarrett Wollman 	   char *gate)
5407b6ab19dSGarrett Wollman {
5417b6ab19dSGarrett Wollman 	static char buf[3*4+3+1+2+3	/* "xxx.xxx.xxx.xxx/xx-->" */
5427b6ab19dSGarrett Wollman 			+3*4+3+1];	/* "xxx.xxx.xxx.xxx" */
5437b6ab19dSGarrett Wollman 	int i;
5447b6ab19dSGarrett Wollman 
5457b6ab19dSGarrett Wollman 	i = sprintf(buf, "%-16s-->", addrname(dst, mask, 0));
5467b6ab19dSGarrett Wollman 	(void)sprintf(&buf[i], "%-*s", 15+20-MAX(20,i), gate);
5477b6ab19dSGarrett Wollman 	return buf;
5487b6ab19dSGarrett Wollman }
5497b6ab19dSGarrett Wollman 
5507b6ab19dSGarrett Wollman 
5517b6ab19dSGarrett Wollman void
5527b6ab19dSGarrett Wollman trace_if(char *act,
5537b6ab19dSGarrett Wollman 	  struct interface *ifp)
5547b6ab19dSGarrett Wollman {
5557b6ab19dSGarrett Wollman 	if (!TRACEACTIONS || ftrace == 0)
5567b6ab19dSGarrett Wollman 		return;
5577b6ab19dSGarrett Wollman 
5587b6ab19dSGarrett Wollman 	lastlog();
559d5b718b3SGarrett Wollman 	(void)fprintf(ftrace, "%-3s interface %-4s ", act, ifp->int_name);
5607b6ab19dSGarrett Wollman 	(void)fprintf(ftrace, "%-15s-->%-15s ",
5617b6ab19dSGarrett Wollman 		      naddr_ntoa(ifp->int_addr),
562d5b718b3SGarrett Wollman 		      addrname(((ifp->int_if_flags & IFF_POINTOPOINT)
5637b6ab19dSGarrett Wollman 				? ifp->int_dstaddr
564d5b718b3SGarrett Wollman 				: htonl(ifp->int_net)),
5657b6ab19dSGarrett Wollman 			       ifp->int_mask, 1));
5667b6ab19dSGarrett Wollman 	if (ifp->int_metric != 0)
5677b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "metric=%d ", ifp->int_metric);
568d5b718b3SGarrett Wollman 	if (!IS_RIP_OUT_OFF(ifp->int_state)
569d5b718b3SGarrett Wollman 	    && ifp->int_d_metric != 0)
570d5b718b3SGarrett Wollman 		(void)fprintf(ftrace, "fake_default=%d ", ifp->int_d_metric);
5717b6ab19dSGarrett Wollman 	trace_bits(if_bits, ifp->int_if_flags, 0);
5727b6ab19dSGarrett Wollman 	trace_bits(is_bits, ifp->int_state, 0);
5737b6ab19dSGarrett Wollman 	(void)fputc('\n',ftrace);
5747b6ab19dSGarrett Wollman }
5757b6ab19dSGarrett Wollman 
5767b6ab19dSGarrett Wollman 
5777b6ab19dSGarrett Wollman void
5787b6ab19dSGarrett Wollman trace_upslot(struct rt_entry *rt,
5797b6ab19dSGarrett Wollman 	     struct rt_spare *rts,
5807b6ab19dSGarrett Wollman 	     naddr	gate,
5817b6ab19dSGarrett Wollman 	     naddr	router,
5827b6ab19dSGarrett Wollman 	     struct interface *ifp,
5837b6ab19dSGarrett Wollman 	     int	metric,
5847b6ab19dSGarrett Wollman 	     u_short	tag,
5857b6ab19dSGarrett Wollman 	     time_t	new_time)
5867b6ab19dSGarrett Wollman {
5877b6ab19dSGarrett Wollman 	if (!TRACEACTIONS || ftrace == 0)
5887b6ab19dSGarrett Wollman 		return;
5897b6ab19dSGarrett Wollman 	if (rts->rts_gate == gate
5907b6ab19dSGarrett Wollman 	    && rts->rts_router == router
5917b6ab19dSGarrett Wollman 	    && rts->rts_metric == metric
5927b6ab19dSGarrett Wollman 	    && rts->rts_tag == tag)
5937b6ab19dSGarrett Wollman 		return;
5947b6ab19dSGarrett Wollman 
5957b6ab19dSGarrett Wollman 	lastlog();
5967b6ab19dSGarrett Wollman 	if (rts->rts_gate != RIP_DEFAULT) {
5977b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "Chg #%d %-35s ",
5987b6ab19dSGarrett Wollman 			      rts - rt->rt_spares,
5997b6ab19dSGarrett Wollman 			      trace_pair(rt->rt_dst, rt->rt_mask,
6007b6ab19dSGarrett Wollman 					 naddr_ntoa(rts->rts_gate)));
6017b6ab19dSGarrett Wollman 		if (rts->rts_gate != rts->rts_gate)
6027b6ab19dSGarrett Wollman 			(void)fprintf(ftrace, "router=%s ",
6037b6ab19dSGarrett Wollman 				      naddr_ntoa(rts->rts_gate));
6047b6ab19dSGarrett Wollman 		if (rts->rts_tag != 0)
6057b6ab19dSGarrett Wollman 			(void)fprintf(ftrace, "tag=%#x ", ntohs(rts->rts_tag));
6067b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "metric=%-2d ", rts->rts_metric);
6077b6ab19dSGarrett Wollman 		if (rts->rts_ifp != 0)
6087b6ab19dSGarrett Wollman 			(void)fprintf(ftrace, "%s ",
6097b6ab19dSGarrett Wollman 				      rts->rts_ifp->int_name);
6107b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "%s\n", ts(rts->rts_time));
6117b6ab19dSGarrett Wollman 
6127b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "       %19s%-16s ",
6137b6ab19dSGarrett Wollman 			      "",
6147b6ab19dSGarrett Wollman 			      gate != rts->rts_gate ? naddr_ntoa(gate) : "");
6157b6ab19dSGarrett Wollman 		if (gate != router)
6167b6ab19dSGarrett Wollman 			(void)fprintf(ftrace,"router=%s ",naddr_ntoa(router));
6177b6ab19dSGarrett Wollman 		if (tag != rts->rts_tag)
6187b6ab19dSGarrett Wollman 			(void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
6197b6ab19dSGarrett Wollman 		if (metric != rts->rts_metric)
6207b6ab19dSGarrett Wollman 			(void)fprintf(ftrace, "metric=%-2d ", metric);
6217b6ab19dSGarrett Wollman 		if (ifp != rts->rts_ifp && ifp != 0 )
6227b6ab19dSGarrett Wollman 			(void)fprintf(ftrace, "%s ", ifp->int_name);
6237b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "%s\n",
6247b6ab19dSGarrett Wollman 			      new_time != rts->rts_time ? ts(new_time) : "");
6257b6ab19dSGarrett Wollman 
6267b6ab19dSGarrett Wollman 	} else {
6277b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "Add #%d %-35s ",
6287b6ab19dSGarrett Wollman 			      rts - rt->rt_spares,
6297b6ab19dSGarrett Wollman 			      trace_pair(rt->rt_dst, rt->rt_mask,
6307b6ab19dSGarrett Wollman 					 naddr_ntoa(gate)));
6317b6ab19dSGarrett Wollman 		if (gate != router)
6327b6ab19dSGarrett Wollman 			(void)fprintf(ftrace, "router=%s ", naddr_ntoa(gate));
6337b6ab19dSGarrett Wollman 		if (tag != 0)
6347b6ab19dSGarrett Wollman 			(void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
6357b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "metric=%-2d ", metric);
6367b6ab19dSGarrett Wollman 		if (ifp != 0)
6377b6ab19dSGarrett Wollman 			(void)fprintf(ftrace, "%s ", ifp->int_name);
6387b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "%s\n", ts(new_time));
6397b6ab19dSGarrett Wollman 	}
6407b6ab19dSGarrett Wollman }
6417b6ab19dSGarrett Wollman 
6427b6ab19dSGarrett Wollman 
6437b6ab19dSGarrett Wollman /* talk about a change made to the kernel table
6447b6ab19dSGarrett Wollman  */
6457b6ab19dSGarrett Wollman void
6467b6ab19dSGarrett Wollman trace_kernel(char *p, ...)
6477b6ab19dSGarrett Wollman {
6487b6ab19dSGarrett Wollman 	va_list args;
6497b6ab19dSGarrett Wollman 
6507b6ab19dSGarrett Wollman 	if (!TRACEKERNEL || ftrace == 0)
6517b6ab19dSGarrett Wollman 		return;
6527b6ab19dSGarrett Wollman 
6537b6ab19dSGarrett Wollman 	lastlog();
6547b6ab19dSGarrett Wollman 	va_start(args, p);
6557b6ab19dSGarrett Wollman 	vfprintf(ftrace, p, args);
6567b6ab19dSGarrett Wollman }
6577b6ab19dSGarrett Wollman 
6587b6ab19dSGarrett Wollman 
6597b6ab19dSGarrett Wollman /* display a message if tracing actions
6607b6ab19dSGarrett Wollman  */
6617b6ab19dSGarrett Wollman void
6627b6ab19dSGarrett Wollman trace_act(char *p, ...)
6637b6ab19dSGarrett Wollman {
6647b6ab19dSGarrett Wollman 	va_list args;
6657b6ab19dSGarrett Wollman 
6667b6ab19dSGarrett Wollman 	if (!TRACEACTIONS || ftrace == 0)
6677b6ab19dSGarrett Wollman 		return;
6687b6ab19dSGarrett Wollman 
6697b6ab19dSGarrett Wollman 	lastlog();
6707b6ab19dSGarrett Wollman 	va_start(args, p);
6717b6ab19dSGarrett Wollman 	vfprintf(ftrace, p, args);
672d5b718b3SGarrett Wollman 	(void)fputc('\n',ftrace);
6737b6ab19dSGarrett Wollman }
6747b6ab19dSGarrett Wollman 
6757b6ab19dSGarrett Wollman 
6767b6ab19dSGarrett Wollman /* display a message if tracing packets
6777b6ab19dSGarrett Wollman  */
6787b6ab19dSGarrett Wollman void
6797b6ab19dSGarrett Wollman trace_pkt(char *p, ...)
6807b6ab19dSGarrett Wollman {
6817b6ab19dSGarrett Wollman 	va_list args;
6827b6ab19dSGarrett Wollman 
6837b6ab19dSGarrett Wollman 	if (!TRACEPACKETS || ftrace == 0)
6847b6ab19dSGarrett Wollman 		return;
6857b6ab19dSGarrett Wollman 
6867b6ab19dSGarrett Wollman 	lastlog();
6877b6ab19dSGarrett Wollman 	va_start(args, p);
6887b6ab19dSGarrett Wollman 	vfprintf(ftrace, p, args);
689d5b718b3SGarrett Wollman 	(void)fputc('\n',ftrace);
6907b6ab19dSGarrett Wollman }
6917b6ab19dSGarrett Wollman 
6927b6ab19dSGarrett Wollman 
6937b6ab19dSGarrett Wollman void
6947b6ab19dSGarrett Wollman trace_change(struct rt_entry *rt,
6957b6ab19dSGarrett Wollman 	     u_int	state,
6967b6ab19dSGarrett Wollman 	     naddr	gate,		/* forward packets here */
6977b6ab19dSGarrett Wollman 	     naddr	router,		/* on the authority of this router */
6987b6ab19dSGarrett Wollman 	     int	metric,
6997b6ab19dSGarrett Wollman 	     u_short	tag,
7007b6ab19dSGarrett Wollman 	     struct interface *ifp,
7017b6ab19dSGarrett Wollman 	     time_t	new_time,
7027b6ab19dSGarrett Wollman 	     char	*label)
7037b6ab19dSGarrett Wollman {
7047b6ab19dSGarrett Wollman 	if (ftrace == 0)
7057b6ab19dSGarrett Wollman 		return;
7067b6ab19dSGarrett Wollman 
7077b6ab19dSGarrett Wollman 	if (rt->rt_metric == metric
7087b6ab19dSGarrett Wollman 	    && rt->rt_gate == gate
7097b6ab19dSGarrett Wollman 	    && rt->rt_router == router
7107b6ab19dSGarrett Wollman 	    && rt->rt_state == state
7117b6ab19dSGarrett Wollman 	    && rt->rt_tag == tag)
7127b6ab19dSGarrett Wollman 		return;
7137b6ab19dSGarrett Wollman 
7147b6ab19dSGarrett Wollman 	lastlog();
7157b6ab19dSGarrett Wollman 	(void)fprintf(ftrace, "%s %-35s metric=%-2d ",
7167b6ab19dSGarrett Wollman 		      label,
7177b6ab19dSGarrett Wollman 		      trace_pair(rt->rt_dst, rt->rt_mask,
7187b6ab19dSGarrett Wollman 				 naddr_ntoa(rt->rt_gate)),
7197b6ab19dSGarrett Wollman 		      rt->rt_metric);
7207b6ab19dSGarrett Wollman 	if (rt->rt_router != rt->rt_gate)
7217b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "router=%s ",
7227b6ab19dSGarrett Wollman 			      naddr_ntoa(rt->rt_router));
7237b6ab19dSGarrett Wollman 	if (rt->rt_tag != 0)
7247b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag));
7257b6ab19dSGarrett Wollman 	trace_bits(rs_bits, rt->rt_state, rt->rt_state != state);
7267b6ab19dSGarrett Wollman 	(void)fprintf(ftrace, "%s ",
7277b6ab19dSGarrett Wollman 		      rt->rt_ifp == 0 ? "?" : rt->rt_ifp->int_name);
7287b6ab19dSGarrett Wollman 	(void)fprintf(ftrace, "%s\n",
7297b6ab19dSGarrett Wollman 		      AGE_RT(rt->rt_state, rt->rt_ifp) ? ts(rt->rt_time) : "");
7307b6ab19dSGarrett Wollman 
7317b6ab19dSGarrett Wollman 	(void)fprintf(ftrace, "%*s %19s%-16s ",
7327b6ab19dSGarrett Wollman 		      strlen(label), "", "",
7337b6ab19dSGarrett Wollman 		      rt->rt_gate != gate ? naddr_ntoa(gate) : "");
7347b6ab19dSGarrett Wollman 	if (rt->rt_metric != metric)
7357b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "metric=%-2d ", metric);
7367b6ab19dSGarrett Wollman 	if (router != gate)
7377b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "router=%s ", naddr_ntoa(router));
7387b6ab19dSGarrett Wollman 	if (rt->rt_tag != tag)
7397b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "tag=%#x ", ntohs(tag));
7407b6ab19dSGarrett Wollman 	if (rt->rt_state != state)
7417b6ab19dSGarrett Wollman 		trace_bits(rs_bits, state, 1);
7427b6ab19dSGarrett Wollman 	if (rt->rt_ifp != ifp)
7437b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "%s ",
7447b6ab19dSGarrett Wollman 			      ifp != 0 ? ifp->int_name : "?");
7457b6ab19dSGarrett Wollman 	(void)fprintf(ftrace, "%s\n",
7467b6ab19dSGarrett Wollman 		      ((rt->rt_time == new_time || !AGE_RT(rt->rt_state, ifp))
7477b6ab19dSGarrett Wollman 		       ? "" : ts(new_time)));
7487b6ab19dSGarrett Wollman }
7497b6ab19dSGarrett Wollman 
7507b6ab19dSGarrett Wollman 
7517b6ab19dSGarrett Wollman void
7527b6ab19dSGarrett Wollman trace_add_del(char * action, struct rt_entry *rt)
7537b6ab19dSGarrett Wollman {
7547b6ab19dSGarrett Wollman 	u_int state = rt->rt_state;
7557b6ab19dSGarrett Wollman 
7567b6ab19dSGarrett Wollman 	if (ftrace == 0)
7577b6ab19dSGarrett Wollman 		return;
7587b6ab19dSGarrett Wollman 
7597b6ab19dSGarrett Wollman 	lastlog();
7607b6ab19dSGarrett Wollman 	(void)fprintf(ftrace, "%s    %-35s metric=%-2d ",
7617b6ab19dSGarrett Wollman 		      action,
7627b6ab19dSGarrett Wollman 		      trace_pair(rt->rt_dst, rt->rt_mask,
7637b6ab19dSGarrett Wollman 				 naddr_ntoa(rt->rt_gate)),
7647b6ab19dSGarrett Wollman 		      rt->rt_metric);
7657b6ab19dSGarrett Wollman 	if (rt->rt_router != rt->rt_gate)
7667b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "router=%s ",
7677b6ab19dSGarrett Wollman 			      naddr_ntoa(rt->rt_router));
7687b6ab19dSGarrett Wollman 	if (rt->rt_tag != 0)
7697b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "tag=%#x ", ntohs(rt->rt_tag));
7707b6ab19dSGarrett Wollman 	trace_bits(rs_bits, state, 0);
7717b6ab19dSGarrett Wollman 	(void)fprintf(ftrace, "%s ",
7727b6ab19dSGarrett Wollman 		      rt->rt_ifp != 0 ? rt->rt_ifp->int_name : "?");
7737b6ab19dSGarrett Wollman 	(void)fprintf(ftrace, "%s\n", ts(rt->rt_time));
7747b6ab19dSGarrett Wollman }
7757b6ab19dSGarrett Wollman 
7767b6ab19dSGarrett Wollman 
7777b6ab19dSGarrett Wollman /* ARGSUSED */
7787b6ab19dSGarrett Wollman static int
7797b6ab19dSGarrett Wollman walk_trace(struct radix_node *rn,
7807b6ab19dSGarrett Wollman 	   struct walkarg *w)
7817b6ab19dSGarrett Wollman {
7827b6ab19dSGarrett Wollman #define RT ((struct rt_entry *)rn)
7837b6ab19dSGarrett Wollman 	struct rt_spare *rts;
7847b6ab19dSGarrett Wollman 	int i, age;
7857b6ab19dSGarrett Wollman 
7867b6ab19dSGarrett Wollman 	(void)fprintf(ftrace, "  %-35s metric=%-2d ",
7877b6ab19dSGarrett Wollman 		      trace_pair(RT->rt_dst, RT->rt_mask,
7887b6ab19dSGarrett Wollman 				 naddr_ntoa(RT->rt_gate)),
7897b6ab19dSGarrett Wollman 		      RT->rt_metric);
7907b6ab19dSGarrett Wollman 	if (RT->rt_router != RT->rt_gate)
7917b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "router=%s ",
7927b6ab19dSGarrett Wollman 			      naddr_ntoa(RT->rt_router));
7937b6ab19dSGarrett Wollman 	if (RT->rt_tag != 0)
7947b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "tag=%#x ",
7957b6ab19dSGarrett Wollman 			      ntohs(RT->rt_tag));
7967b6ab19dSGarrett Wollman 	trace_bits(rs_bits, RT->rt_state, 0);
7977b6ab19dSGarrett Wollman 	(void)fprintf(ftrace, "%s ",
7987b6ab19dSGarrett Wollman 		      RT->rt_ifp == 0 ? "?" : RT->rt_ifp->int_name);
7997b6ab19dSGarrett Wollman 	age = AGE_RT(RT->rt_state, RT->rt_ifp);
8007b6ab19dSGarrett Wollman 	if (age)
8017b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "%s", ts(RT->rt_time));
8027b6ab19dSGarrett Wollman 
8037b6ab19dSGarrett Wollman 	rts = &RT->rt_spares[1];
8047b6ab19dSGarrett Wollman 	for (i = 1; i < NUM_SPARES; i++, rts++) {
8057b6ab19dSGarrett Wollman 		if (rts->rts_metric != HOPCNT_INFINITY) {
8067b6ab19dSGarrett Wollman 			(void)fprintf(ftrace,"\n    #%d%15s%-16s metric=%-2d ",
8077b6ab19dSGarrett Wollman 				      i, "", naddr_ntoa(rts->rts_gate),
8087b6ab19dSGarrett Wollman 				      rts->rts_metric);
8097b6ab19dSGarrett Wollman 			if (rts->rts_router != rts->rts_gate)
8107b6ab19dSGarrett Wollman 				(void)fprintf(ftrace, "router=%s ",
8117b6ab19dSGarrett Wollman 					      naddr_ntoa(rts->rts_router));
8127b6ab19dSGarrett Wollman 			if (rts->rts_tag != 0)
8137b6ab19dSGarrett Wollman 				(void)fprintf(ftrace, "tag=%#x ",
8147b6ab19dSGarrett Wollman 					      ntohs(rts->rts_tag));
8157b6ab19dSGarrett Wollman 			(void)fprintf(ftrace, "%s ",
8167b6ab19dSGarrett Wollman 				      (rts->rts_ifp == 0
8177b6ab19dSGarrett Wollman 				       ? "?" : rts->rts_ifp->int_name));
8187b6ab19dSGarrett Wollman 			if (age)
8197b6ab19dSGarrett Wollman 				(void)fprintf(ftrace, "%s", ts(rts->rts_time));
8207b6ab19dSGarrett Wollman 		}
8217b6ab19dSGarrett Wollman 	}
8227b6ab19dSGarrett Wollman 	(void)fputc('\n',ftrace);
8237b6ab19dSGarrett Wollman 
8247b6ab19dSGarrett Wollman 	return 0;
8257b6ab19dSGarrett Wollman }
8267b6ab19dSGarrett Wollman 
8277b6ab19dSGarrett Wollman 
8287b6ab19dSGarrett Wollman static void
8297b6ab19dSGarrett Wollman trace_dump(void)
8307b6ab19dSGarrett Wollman {
831d5b718b3SGarrett Wollman 	struct interface *ifp;
832d5b718b3SGarrett Wollman 
8337b6ab19dSGarrett Wollman 	if (ftrace == 0)
8347b6ab19dSGarrett Wollman 		return;
8357b6ab19dSGarrett Wollman 	lastlog();
8367b6ab19dSGarrett Wollman 
837d5b718b3SGarrett Wollman 	for (ifp = ifnet; ifp != 0; ifp = ifp->int_next)
838d5b718b3SGarrett Wollman 		trace_if("", ifp);
8397b6ab19dSGarrett Wollman 	(void)rn_walktree(rhead, walk_trace, 0);
8407b6ab19dSGarrett Wollman }
8417b6ab19dSGarrett Wollman 
8427b6ab19dSGarrett Wollman 
8437b6ab19dSGarrett Wollman void
8447b6ab19dSGarrett Wollman trace_rip(char *dir1, char *dir2,
8457b6ab19dSGarrett Wollman 	  struct sockaddr_in *who,
8467b6ab19dSGarrett Wollman 	  struct interface *ifp,
8477b6ab19dSGarrett Wollman 	  struct rip *msg,
8487b6ab19dSGarrett Wollman 	  int size)			/* total size of message */
8497b6ab19dSGarrett Wollman {
8507b6ab19dSGarrett Wollman 	struct netinfo *n, *lim;
851d5b718b3SGarrett Wollman #	define NA (msg->rip_auths)
852d5b718b3SGarrett Wollman 	int i, seen_route;
8537b6ab19dSGarrett Wollman 
8547b6ab19dSGarrett Wollman 	if (!TRACEPACKETS || ftrace == 0)
8557b6ab19dSGarrett Wollman 		return;
8567b6ab19dSGarrett Wollman 
8577b6ab19dSGarrett Wollman 	lastlog();
8587b6ab19dSGarrett Wollman 	if (msg->rip_cmd >= RIPCMD_MAX
8597b6ab19dSGarrett Wollman 	    || msg->rip_vers == 0) {
8607b6ab19dSGarrett Wollman 		(void)fprintf(ftrace, "%s bad RIPv%d cmd=%d %s"
8617b6ab19dSGarrett Wollman 			      " %s.%d size=%d\n",
8627b6ab19dSGarrett Wollman 			      dir1, msg->rip_vers, msg->rip_cmd, dir2,
8637b6ab19dSGarrett Wollman 			      naddr_ntoa(who->sin_addr.s_addr),
8647b6ab19dSGarrett Wollman 			      ntohs(who->sin_port),
8657b6ab19dSGarrett Wollman 			      size);
8667b6ab19dSGarrett Wollman 		return;
8677b6ab19dSGarrett Wollman 	}
8687b6ab19dSGarrett Wollman 
8697b6ab19dSGarrett Wollman 	(void)fprintf(ftrace, "%s RIPv%d %s %s %s.%d%s%s\n",
8707b6ab19dSGarrett Wollman 		      dir1, msg->rip_vers, ripcmds[msg->rip_cmd], dir2,
8717b6ab19dSGarrett Wollman 		      naddr_ntoa(who->sin_addr.s_addr), ntohs(who->sin_port),
8727b6ab19dSGarrett Wollman 		      ifp ? " via " : "", ifp ? ifp->int_name : "");
8737b6ab19dSGarrett Wollman 	if (!TRACECONTENTS)
8747b6ab19dSGarrett Wollman 		return;
8757b6ab19dSGarrett Wollman 
876d5b718b3SGarrett Wollman 	seen_route = 0;
8777b6ab19dSGarrett Wollman 	switch (msg->rip_cmd) {
8787b6ab19dSGarrett Wollman 	case RIPCMD_REQUEST:
8797b6ab19dSGarrett Wollman 	case RIPCMD_RESPONSE:
8807b6ab19dSGarrett Wollman 		n = msg->rip_nets;
8817b6ab19dSGarrett Wollman 		lim = (struct netinfo *)((char*)msg + size);
8827b6ab19dSGarrett Wollman 		for (; n < lim; n++) {
883d5b718b3SGarrett Wollman 			if (!seen_route
884d5b718b3SGarrett Wollman 			    && n->n_family == RIP_AF_UNSPEC
8857b6ab19dSGarrett Wollman 			    && ntohl(n->n_metric) == HOPCNT_INFINITY
886d5b718b3SGarrett Wollman 			    && msg->rip_cmd == RIPCMD_REQUEST
887d5b718b3SGarrett Wollman 			    && (n+1 == lim
888d5b718b3SGarrett Wollman 				|| (n+2 == lim
889d5b718b3SGarrett Wollman 				    && (n+1)->n_family == RIP_AF_AUTH))) {
8907b6ab19dSGarrett Wollman 				(void)fputs("\tQUERY ", ftrace);
8917b6ab19dSGarrett Wollman 				if (n->n_dst != 0)
8927b6ab19dSGarrett Wollman 					(void)fprintf(ftrace, "%s ",
8937b6ab19dSGarrett Wollman 						      naddr_ntoa(n->n_dst));
8947b6ab19dSGarrett Wollman 				if (n->n_mask != 0)
8957b6ab19dSGarrett Wollman 					(void)fprintf(ftrace, "mask=%#x ",
8967b6ab19dSGarrett Wollman 						      (u_int)ntohl(n->n_mask));
8977b6ab19dSGarrett Wollman 				if (n->n_nhop != 0)
8987b6ab19dSGarrett Wollman 					(void)fprintf(ftrace, "nhop=%s ",
8997b6ab19dSGarrett Wollman 						      naddr_ntoa(n->n_nhop));
9007b6ab19dSGarrett Wollman 				if (n->n_tag != 0)
9017b6ab19dSGarrett Wollman 					(void)fprintf(ftrace, "tag=%#x ",
9027b6ab19dSGarrett Wollman 						      ntohs(n->n_tag));
9037b6ab19dSGarrett Wollman 				(void)fputc('\n',ftrace);
9047b6ab19dSGarrett Wollman 				continue;
9057b6ab19dSGarrett Wollman 			}
9067b6ab19dSGarrett Wollman 
9077b6ab19dSGarrett Wollman 			if (n->n_family == RIP_AF_AUTH) {
908d5b718b3SGarrett Wollman 				if (NA->a_type == RIP_AUTH_PW
909d5b718b3SGarrett Wollman 				    && n == msg->rip_nets) {
910d5b718b3SGarrett Wollman 					(void)fprintf(ftrace, "\tPassword"
911d5b718b3SGarrett Wollman 						      " Authentication:"
912d5b718b3SGarrett Wollman 						      " \"%s\"\n",
913d5b718b3SGarrett Wollman 						      qstring(NA->au.au_pw,
914d5b718b3SGarrett Wollman 							  RIP_AUTH_PW_LEN));
915d5b718b3SGarrett Wollman 					continue;
916d5b718b3SGarrett Wollman 				}
917d5b718b3SGarrett Wollman 
918d5b718b3SGarrett Wollman 				if (NA->a_type == RIP_AUTH_MD5
919d5b718b3SGarrett Wollman 				    && n == msg->rip_nets) {
9207b6ab19dSGarrett Wollman 					(void)fprintf(ftrace,
921d5b718b3SGarrett Wollman 						      "\tMD5 Authentication"
922d5b718b3SGarrett Wollman 						      " len=%d KeyID=%u"
923d5b718b3SGarrett Wollman 						      " seqno=%u"
924d5b718b3SGarrett Wollman 						      " rsvd=%#x,%#x\n",
925d5b718b3SGarrett Wollman 						      NA->au.a_md5.md5_pkt_len,
926d5b718b3SGarrett Wollman 						      NA->au.a_md5.md5_keyid,
927d5b718b3SGarrett Wollman 						      NA->au.a_md5.md5_seqno,
928d5b718b3SGarrett Wollman 						      NA->au.a_md5.rsvd[0],
929d5b718b3SGarrett Wollman 						      NA->au.a_md5.rsvd[1]);
930d5b718b3SGarrett Wollman 					continue;
931d5b718b3SGarrett Wollman 				}
932d5b718b3SGarrett Wollman 				(void)fprintf(ftrace,
933d5b718b3SGarrett Wollman 					      "\tAuthentication"
934d5b718b3SGarrett Wollman 					      " type %d: ",
935d5b718b3SGarrett Wollman 					      ntohs(NA->a_type));
9367b6ab19dSGarrett Wollman 				for (i = 0;
937d5b718b3SGarrett Wollman 				     i < sizeof(NA->au.au_pw);
9387b6ab19dSGarrett Wollman 				     i++)
9397b6ab19dSGarrett Wollman 					(void)fprintf(ftrace, "%02x ",
940d5b718b3SGarrett Wollman 						      NA->au.au_pw[i]);
9417b6ab19dSGarrett Wollman 				(void)fputc('\n',ftrace);
9427b6ab19dSGarrett Wollman 				continue;
9437b6ab19dSGarrett Wollman 			}
9447b6ab19dSGarrett Wollman 
945d5b718b3SGarrett Wollman 			seen_route = 1;
9467b6ab19dSGarrett Wollman 			if (n->n_family != RIP_AF_INET) {
9477b6ab19dSGarrett Wollman 				(void)fprintf(ftrace,
9487b6ab19dSGarrett Wollman 					      "\t(af %d) %-18s mask=%#x ",
9497b6ab19dSGarrett Wollman 					      ntohs(n->n_family),
9507b6ab19dSGarrett Wollman 					      naddr_ntoa(n->n_dst),
9517b6ab19dSGarrett Wollman 					      (u_int)ntohl(n->n_mask));
9527b6ab19dSGarrett Wollman 			} else if (msg->rip_vers == RIPv1) {
9537b6ab19dSGarrett Wollman 				(void)fprintf(ftrace, "\t%-18s ",
9547b6ab19dSGarrett Wollman 					      addrname(n->n_dst,
9557b6ab19dSGarrett Wollman 						       ntohl(n->n_mask),
9567b6ab19dSGarrett Wollman 						       n->n_mask==0 ? 2 : 1));
9577b6ab19dSGarrett Wollman 			} else {
9587b6ab19dSGarrett Wollman 				(void)fprintf(ftrace, "\t%-18s ",
9597b6ab19dSGarrett Wollman 					      addrname(n->n_dst,
9607b6ab19dSGarrett Wollman 						       ntohl(n->n_mask),
9617b6ab19dSGarrett Wollman 						       n->n_mask==0 ? 2 : 0));
9627b6ab19dSGarrett Wollman 			}
9637b6ab19dSGarrett Wollman 			(void)fprintf(ftrace, "metric=%-2d ",
9647b6ab19dSGarrett Wollman 				      (u_int)ntohl(n->n_metric));
9657b6ab19dSGarrett Wollman 			if (n->n_nhop != 0)
9667b6ab19dSGarrett Wollman 				(void)fprintf(ftrace, " nhop=%s ",
9677b6ab19dSGarrett Wollman 					      naddr_ntoa(n->n_nhop));
9687b6ab19dSGarrett Wollman 			if (n->n_tag != 0)
9697b6ab19dSGarrett Wollman 				(void)fprintf(ftrace, "tag=%#x",
9707b6ab19dSGarrett Wollman 					      ntohs(n->n_tag));
9717b6ab19dSGarrett Wollman 			(void)fputc('\n',ftrace);
9727b6ab19dSGarrett Wollman 		}
9737b6ab19dSGarrett Wollman 		if (size != (char *)n - (char *)msg)
9747b6ab19dSGarrett Wollman 			(void)fprintf(ftrace, "truncated record, len %d\n",
9757b6ab19dSGarrett Wollman 				size);
9767b6ab19dSGarrett Wollman 		break;
9777b6ab19dSGarrett Wollman 
9787b6ab19dSGarrett Wollman 	case RIPCMD_TRACEON:
9797b6ab19dSGarrett Wollman 		fprintf(ftrace, "\tfile=%*s\n", size-4, msg->rip_tracefile);
9807b6ab19dSGarrett Wollman 		break;
9817b6ab19dSGarrett Wollman 
9827b6ab19dSGarrett Wollman 	case RIPCMD_TRACEOFF:
9837b6ab19dSGarrett Wollman 		break;
9847b6ab19dSGarrett Wollman 	}
9857b6ab19dSGarrett Wollman }
986