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