17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bdstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bdstevel@tonic-gate * (the "License").  You may not use this file except in compliance
77c478bdstevel@tonic-gate * with the License.
87c478bdstevel@tonic-gate *
97c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bdstevel@tonic-gate * See the License for the specific language governing permissions
127c478bdstevel@tonic-gate * and limitations under the License.
137c478bdstevel@tonic-gate *
147c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bdstevel@tonic-gate *
207c478bdstevel@tonic-gate * CDDL HEADER END
217c478bdstevel@tonic-gate */
227c478bdstevel@tonic-gate/*
237c478bdstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bdstevel@tonic-gate * Use is subject to license terms.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
287c478bdstevel@tonic-gate/*	  All Rights Reserved  	*/
297c478bdstevel@tonic-gate
307c478bdstevel@tonic-gate/*
317c478bdstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD
327c478bdstevel@tonic-gate * under license from the Regents of the University of California.
337c478bdstevel@tonic-gate */
347c478bdstevel@tonic-gate
357c478bdstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.1	*/
367c478bdstevel@tonic-gate
377c478bdstevel@tonic-gate/*
387c478bdstevel@tonic-gate * Routing Table Management Daemon
397c478bdstevel@tonic-gate */
407c478bdstevel@tonic-gate#include "defs.h"
417c478bdstevel@tonic-gate
427c478bdstevel@tonic-gate#define	NRECORDS	50		/* size of circular trace buffer */
437c478bdstevel@tonic-gate
447c478bdstevel@tonic-gateboolean_t	tracepackets;		/* watch packets as they go by */
457c478bdstevel@tonic-gateint		tracing;		/* bitmask: */
467c478bdstevel@tonic-gateFILE		*ftrace;		/* output trace file */
477c478bdstevel@tonic-gate
487c478bdstevel@tonic-gatestatic int	iftraceinit(struct interface *ifp, struct ifdebug *ifd);
497c478bdstevel@tonic-gatestatic void	dumpif(FILE *fp, struct interface *ifp);
507c478bdstevel@tonic-gatestatic void	dumptrace(FILE *fp, char *dir, struct ifdebug *ifd);
517c478bdstevel@tonic-gate
527c478bdstevel@tonic-gatevoid
537c478bdstevel@tonic-gatetraceinit(struct interface *ifp)
547c478bdstevel@tonic-gate{
557c478bdstevel@tonic-gate	if (iftraceinit(ifp, &ifp->int_input) &&
567c478bdstevel@tonic-gate	    iftraceinit(ifp, &ifp->int_output))
577c478bdstevel@tonic-gate		return;
587c478bdstevel@tonic-gate	tracing = 0;
597c478bdstevel@tonic-gate	(void) fprintf(stderr, "traceinit: can't init %s\n",
607c478bdstevel@tonic-gate	    (ifp->int_name != NULL) ? ifp->int_name : "(noname)");
617c478bdstevel@tonic-gate}
627c478bdstevel@tonic-gate
637c478bdstevel@tonic-gatestatic int
647c478bdstevel@tonic-gateiftraceinit(struct interface *ifp, struct ifdebug *ifd)
657c478bdstevel@tonic-gate{
667c478bdstevel@tonic-gate	struct iftrace *t;
677c478bdstevel@tonic-gate
687c478bdstevel@tonic-gate	ifd->ifd_records = (struct iftrace *)
697c478bdstevel@tonic-gate	    malloc((size_t)NRECORDS * sizeof (struct iftrace));
707c478bdstevel@tonic-gate	if (ifd->ifd_records == NULL)
717c478bdstevel@tonic-gate		return (0);
727c478bdstevel@tonic-gate	ifd->ifd_front = ifd->ifd_records;
737c478bdstevel@tonic-gate	ifd->ifd_count = 0;
747c478bdstevel@tonic-gate	for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
757c478bdstevel@tonic-gate		t->ift_size = 0;
767c478bdstevel@tonic-gate		t->ift_packet = NULL;
777c478bdstevel@tonic-gate	}
787c478bdstevel@tonic-gate	ifd->ifd_if = ifp;
797c478bdstevel@tonic-gate	return (1);
807c478bdstevel@tonic-gate}
817c478bdstevel@tonic-gate
827c478bdstevel@tonic-gatevoid
837c478bdstevel@tonic-gatetraceon(char *file)
847c478bdstevel@tonic-gate{
857c478bdstevel@tonic-gate	struct stat stbuf;
867c478bdstevel@tonic-gate
877c478bdstevel@tonic-gate	if (ftrace != NULL)
887c478bdstevel@tonic-gate		return;
897c478bdstevel@tonic-gate	if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG)
907c478bdstevel@tonic-gate		return;
917c478bdstevel@tonic-gate	ftrace = fopen(file, "a");
927c478bdstevel@tonic-gate	if (ftrace == NULL)
937c478bdstevel@tonic-gate		return;
947c478bdstevel@tonic-gate	(void) dup2(fileno(ftrace), 1);
957c478bdstevel@tonic-gate	(void) dup2(fileno(ftrace), 2);
967c478bdstevel@tonic-gate}
977c478bdstevel@tonic-gate
987c478bdstevel@tonic-gatevoid
997c478bdstevel@tonic-gatetraceonfp(FILE *fp)
1007c478bdstevel@tonic-gate{
1017c478bdstevel@tonic-gate	if (ftrace != NULL)
1027c478bdstevel@tonic-gate		return;
1037c478bdstevel@tonic-gate	ftrace = fp;
1047c478bdstevel@tonic-gate	if (ftrace == NULL)
1057c478bdstevel@tonic-gate		return;
1067c478bdstevel@tonic-gate	(void) dup2(fileno(ftrace), 1);
1077c478bdstevel@tonic-gate	(void) dup2(fileno(ftrace), 2);
1087c478bdstevel@tonic-gate}
1097c478bdstevel@tonic-gate
1107c478bdstevel@tonic-gatevoid
1117c478bdstevel@tonic-gatetrace(struct ifdebug *ifd, struct sockaddr_in6 *who, char *p, int len, int m)
1127c478bdstevel@tonic-gate{
1137c478bdstevel@tonic-gate	struct iftrace *t;
1147c478bdstevel@tonic-gate
1157c478bdstevel@tonic-gate	if (ifd->ifd_records == 0)
1167c478bdstevel@tonic-gate		return;
1177c478bdstevel@tonic-gate	t = ifd->ifd_front++;
1187c478bdstevel@tonic-gate	if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
1197c478bdstevel@tonic-gate		ifd->ifd_front = ifd->ifd_records;
1207c478bdstevel@tonic-gate	if (ifd->ifd_count < NRECORDS)
1217c478bdstevel@tonic-gate		ifd->ifd_count++;
1227c478bdstevel@tonic-gate	if (t->ift_size > 0 && t->ift_size < len && t->ift_packet != NULL) {
1237c478bdstevel@tonic-gate		free(t->ift_packet);
1247c478bdstevel@tonic-gate		t->ift_packet = NULL;
1257c478bdstevel@tonic-gate	}
1267c478bdstevel@tonic-gate	(void) time(&t->ift_stamp);
1277c478bdstevel@tonic-gate	t->ift_who = *who;
1287c478bdstevel@tonic-gate	if (len > 0 && t->ift_packet == NULL) {
1297c478bdstevel@tonic-gate		t->ift_packet = (char *)malloc((size_t)len);
1307c478bdstevel@tonic-gate		if (t->ift_packet == NULL)
1317c478bdstevel@tonic-gate			len = 0;
1327c478bdstevel@tonic-gate	}
1337c478bdstevel@tonic-gate	if (len > 0)
1347c478bdstevel@tonic-gate		bcopy(p, t->ift_packet, len);
1357c478bdstevel@tonic-gate	t->ift_size = len;
1367c478bdstevel@tonic-gate	t->ift_metric = m;
1377c478bdstevel@tonic-gate}
1387c478bdstevel@tonic-gate
1397c478bdstevel@tonic-gatevoid
1407c478bdstevel@tonic-gatetraceaction(FILE *fp, char *action, struct rt_entry *rt)
1417c478bdstevel@tonic-gate{
1427c478bdstevel@tonic-gate	static struct bits {
1437c478bdstevel@tonic-gate		ulong_t	t_bits;
1447c478bdstevel@tonic-gate		char	*t_name;
1457c478bdstevel@tonic-gate	} flagbits[] = {
1467c478bdstevel@tonic-gate		/* BEGIN CSTYLED */
1477c478bdstevel@tonic-gate		{ RTF_UP,		"UP" },
1487c478bdstevel@tonic-gate		{ RTF_GATEWAY,		"GATEWAY" },
1497c478bdstevel@tonic-gate		{ RTF_HOST,		"HOST" },
1507c478bdstevel@tonic-gate		{ 0,			NULL }
1517c478bdstevel@tonic-gate		/* END CSTYLED */
1527c478bdstevel@tonic-gate	}, statebits[] = {
1537c478bdstevel@tonic-gate		/* BEGIN CSTYLED */
1547c478bdstevel@tonic-gate		{ RTS_INTERFACE,	"INTERFACE" },
1557c478bdstevel@tonic-gate		{ RTS_CHANGED,		"CHANGED" },
1567c478bdstevel@tonic-gate		{ RTS_PRIVATE,		"PRIVATE" },
1577c478bdstevel@tonic-gate		{ 0,			NULL }
1587c478bdstevel@tonic-gate		/* END CSTYLED */
1597c478bdstevel@tonic-gate	};
1607c478bdstevel@tonic-gate	struct bits *p;
1617c478bdstevel@tonic-gate	boolean_t first;
1627c478bdstevel@tonic-gate	char c;
1637c478bdstevel@tonic-gate	time_t t;
1647c478bdstevel@tonic-gate
1657c478bdstevel@tonic-gate	if (fp == NULL)
1667c478bdstevel@tonic-gate		return;
1677c478bdstevel@tonic-gate	(void) time(&t);
1687c478bdstevel@tonic-gate	(void) fprintf(fp, "%.15s %s ", ctime(&t) + 4, action);
1697c478bdstevel@tonic-gate	if (rt != NULL) {
1707c478bdstevel@tonic-gate		char buf1[INET6_ADDRSTRLEN];
1717c478bdstevel@tonic-gate
1727c478bdstevel@tonic-gate		(void) fprintf(fp, "prefix %s/%d ",
1737c478bdstevel@tonic-gate		    inet_ntop(AF_INET6, (void *)&rt->rt_dst, buf1,
1747c478bdstevel@tonic-gate			sizeof (buf1)),
1757c478bdstevel@tonic-gate		    rt->rt_prefix_length);
1767c478bdstevel@tonic-gate		(void) fprintf(fp, "via %s metric %d",
1777c478bdstevel@tonic-gate		    inet_ntop(AF_INET6, (void *)&rt->rt_router, buf1,
1787c478bdstevel@tonic-gate			sizeof (buf1)),
1797c478bdstevel@tonic-gate		    rt->rt_metric);
1807c478bdstevel@tonic-gate		if (rt->rt_ifp != NULL) {
1817c478bdstevel@tonic-gate			(void) fprintf(fp, " if %s",
1827c478bdstevel@tonic-gate			    (rt->rt_ifp->int_name != NULL) ?
1837c478bdstevel@tonic-gate				rt->rt_ifp->int_name : "(noname)");
1847c478bdstevel@tonic-gate		}
1857c478bdstevel@tonic-gate		(void) fprintf(fp, " state");
1867c478bdstevel@tonic-gate		c = ' ';
1877c478bdstevel@tonic-gate		for (first = _B_TRUE, p = statebits; p->t_bits > 0; p++) {
1887c478bdstevel@tonic-gate			if ((rt->rt_state & p->t_bits) == 0)
1897c478bdstevel@tonic-gate				continue;
1907c478bdstevel@tonic-gate			(void) fprintf(fp, "%c%s", c, p->t_name);
1917c478bdstevel@tonic-gate			if (first) {
1927c478bdstevel@tonic-gate				c = '|';
1937c478bdstevel@tonic-gate				first = _B_FALSE;
1947c478bdstevel@tonic-gate			}
1957c478bdstevel@tonic-gate		}
1967c478bdstevel@tonic-gate		if (first)
1977c478bdstevel@tonic-gate			(void) fprintf(fp, " 0");
1987c478bdstevel@tonic-gate		if (rt->rt_flags & (RTF_UP | RTF_GATEWAY)) {
1997c478bdstevel@tonic-gate			c = ' ';
2007c478bdstevel@tonic-gate			for (first = _B_TRUE, p = flagbits; p->t_bits > 0;
2017c478bdstevel@tonic-gate			    p++) {
2027c478bdstevel@tonic-gate				if ((rt->rt_flags & p->t_bits) == 0)
2037c478bdstevel@tonic-gate					continue;
2047c478bdstevel@tonic-gate				(void) fprintf(fp, "%c%s", c, p->t_name);
2057c478bdstevel@tonic-gate				if (first) {
2067c478bdstevel@tonic-gate					c = '|';
2077c478bdstevel@tonic-gate					first = _B_FALSE;
2087c478bdstevel@tonic-gate				}
2097c478bdstevel@tonic-gate			}
2107c478bdstevel@tonic-gate		}
2117c478bdstevel@tonic-gate	}
2127c478bdstevel@tonic-gate	(void) putc('\n', fp);
2137c478bdstevel@tonic-gate	if (!tracepackets && rt != NULL && rt->rt_ifp != NULL)
2147c478bdstevel@tonic-gate		dumpif(fp, rt->rt_ifp);
2157c478bdstevel@tonic-gate	(void) fflush(fp);
2167c478bdstevel@tonic-gate}
2177c478bdstevel@tonic-gate
2187c478bdstevel@tonic-gatestatic void
2197c478bdstevel@tonic-gatedumpif(FILE *fp, struct interface *ifp)
2207c478bdstevel@tonic-gate{
2217c478bdstevel@tonic-gate	if (ifp->int_input.ifd_count != 0 || ifp->int_output.ifd_count != 0) {
2227c478bdstevel@tonic-gate		(void) fprintf(fp, "*** Packet history for interface %s ***\n",
2237c478bdstevel@tonic-gate		    (ifp->int_name != NULL) ? ifp->int_name : "(noname)");
2247c478bdstevel@tonic-gate		dumptrace(fp, "to", &ifp->int_output);
2257c478bdstevel@tonic-gate		dumptrace(fp, "from", &ifp->int_input);
2267c478bdstevel@tonic-gate		(void) fprintf(fp, "*** end packet history ***\n");
2277c478bdstevel@tonic-gate	}
2287c478bdstevel@tonic-gate	(void) fflush(fp);
2297c478bdstevel@tonic-gate}
2307c478bdstevel@tonic-gate
2317c478bdstevel@tonic-gatestatic void
2327c478bdstevel@tonic-gatedumptrace(FILE *fp, char *dir, struct ifdebug *ifd)
2337c478bdstevel@tonic-gate{
2347c478bdstevel@tonic-gate	struct iftrace *t;
2357c478bdstevel@tonic-gate	char *cp = (strcmp(dir, "to") != 0) ? "Output" : "Input";
2367c478bdstevel@tonic-gate
2377c478bdstevel@tonic-gate	if (ifd->ifd_front == ifd->ifd_records &&
2387c478bdstevel@tonic-gate	    ifd->ifd_front->ift_size == 0) {
2397c478bdstevel@tonic-gate		(void) fprintf(fp, "%s: no packets.\n", cp);
2407c478bdstevel@tonic-gate		(void) fflush(fp);
2417c478bdstevel@tonic-gate		return;
2427c478bdstevel@tonic-gate	}
2437c478bdstevel@tonic-gate	(void) fprintf(fp, "%s trace:\n", cp);
2447c478bdstevel@tonic-gate	t = ifd->ifd_front - ifd->ifd_count;
2457c478bdstevel@tonic-gate	if (t < ifd->ifd_records)
2467c478bdstevel@tonic-gate		t += NRECORDS;
2477c478bdstevel@tonic-gate	for (; ifd->ifd_count; ifd->ifd_count--, t++) {
2487c478bdstevel@tonic-gate		if (t >= ifd->ifd_records + NRECORDS)
2497c478bdstevel@tonic-gate			t = ifd->ifd_records;
2507c478bdstevel@tonic-gate		if (t->ift_size == 0)
2517c478bdstevel@tonic-gate			continue;
2527c478bdstevel@tonic-gate		(void) fprintf(fp, "%.24s: metric=%d\n", ctime(&t->ift_stamp),
2537c478bdstevel@tonic-gate		    t->ift_metric);
2547c478bdstevel@tonic-gate		dumppacket(fp, dir, (struct sockaddr_in6 *)&t->ift_who,
2557c478bdstevel@tonic-gate		    t->ift_packet, t->ift_size);
2567c478bdstevel@tonic-gate	}
2577c478bdstevel@tonic-gate}
2587c478bdstevel@tonic-gate
2597c478bdstevel@tonic-gate/*ARGSUSED*/
2607c478bdstevel@tonic-gatevoid
2617c478bdstevel@tonic-gatedumppacket(FILE *fp, char *dir, struct sockaddr_in6 *who, char *cp, int size)
2627c478bdstevel@tonic-gate{
2637c478bdstevel@tonic-gate	/* XXX Output contents of the RIP packet */
2647c478bdstevel@tonic-gate}
265