1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28/*	  All Rights Reserved  	*/
29
30/*
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
33 */
34
35#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.1	*/
36
37/*
38 * Routing Table Management Daemon
39 */
40#include "defs.h"
41
42#define	NRECORDS	50		/* size of circular trace buffer */
43
44boolean_t	tracepackets;		/* watch packets as they go by */
45int		tracing;		/* bitmask: */
46FILE		*ftrace;		/* output trace file */
47
48static int	iftraceinit(struct interface *ifp, struct ifdebug *ifd);
49static void	dumpif(FILE *fp, struct interface *ifp);
50static void	dumptrace(FILE *fp, char *dir, struct ifdebug *ifd);
51
52void
53traceinit(struct interface *ifp)
54{
55	if (iftraceinit(ifp, &ifp->int_input) &&
56	    iftraceinit(ifp, &ifp->int_output))
57		return;
58	tracing = 0;
59	(void) fprintf(stderr, "traceinit: can't init %s\n",
60	    (ifp->int_name != NULL) ? ifp->int_name : "(noname)");
61}
62
63static int
64iftraceinit(struct interface *ifp, struct ifdebug *ifd)
65{
66	struct iftrace *t;
67
68	ifd->ifd_records = (struct iftrace *)
69	    malloc((size_t)NRECORDS * sizeof (struct iftrace));
70	if (ifd->ifd_records == NULL)
71		return (0);
72	ifd->ifd_front = ifd->ifd_records;
73	ifd->ifd_count = 0;
74	for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
75		t->ift_size = 0;
76		t->ift_packet = NULL;
77	}
78	ifd->ifd_if = ifp;
79	return (1);
80}
81
82void
83traceon(char *file)
84{
85	struct stat stbuf;
86
87	if (ftrace != NULL)
88		return;
89	if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG)
90		return;
91	ftrace = fopen(file, "a");
92	if (ftrace == NULL)
93		return;
94	(void) dup2(fileno(ftrace), 1);
95	(void) dup2(fileno(ftrace), 2);
96}
97
98void
99traceonfp(FILE *fp)
100{
101	if (ftrace != NULL)
102		return;
103	ftrace = fp;
104	if (ftrace == NULL)
105		return;
106	(void) dup2(fileno(ftrace), 1);
107	(void) dup2(fileno(ftrace), 2);
108}
109
110void
111trace(struct ifdebug *ifd, struct sockaddr_in6 *who, char *p, int len, int m)
112{
113	struct iftrace *t;
114
115	if (ifd->ifd_records == 0)
116		return;
117	t = ifd->ifd_front++;
118	if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
119		ifd->ifd_front = ifd->ifd_records;
120	if (ifd->ifd_count < NRECORDS)
121		ifd->ifd_count++;
122	if (t->ift_size > 0 && t->ift_size < len && t->ift_packet != NULL) {
123		free(t->ift_packet);
124		t->ift_packet = NULL;
125	}
126	(void) time(&t->ift_stamp);
127	t->ift_who = *who;
128	if (len > 0 && t->ift_packet == NULL) {
129		t->ift_packet = (char *)malloc((size_t)len);
130		if (t->ift_packet == NULL)
131			len = 0;
132	}
133	if (len > 0)
134		bcopy(p, t->ift_packet, len);
135	t->ift_size = len;
136	t->ift_metric = m;
137}
138
139void
140traceaction(FILE *fp, char *action, struct rt_entry *rt)
141{
142	static struct bits {
143		ulong_t	t_bits;
144		char	*t_name;
145	} flagbits[] = {
146		/* BEGIN CSTYLED */
147		{ RTF_UP,		"UP" },
148		{ RTF_GATEWAY,		"GATEWAY" },
149		{ RTF_HOST,		"HOST" },
150		{ 0,			NULL }
151		/* END CSTYLED */
152	}, statebits[] = {
153		/* BEGIN CSTYLED */
154		{ RTS_INTERFACE,	"INTERFACE" },
155		{ RTS_CHANGED,		"CHANGED" },
156		{ RTS_PRIVATE,		"PRIVATE" },
157		{ 0,			NULL }
158		/* END CSTYLED */
159	};
160	struct bits *p;
161	boolean_t first;
162	char c;
163	time_t t;
164
165	if (fp == NULL)
166		return;
167	(void) time(&t);
168	(void) fprintf(fp, "%.15s %s ", ctime(&t) + 4, action);
169	if (rt != NULL) {
170		char buf1[INET6_ADDRSTRLEN];
171
172		(void) fprintf(fp, "prefix %s/%d ",
173		    inet_ntop(AF_INET6, (void *)&rt->rt_dst, buf1,
174			sizeof (buf1)),
175		    rt->rt_prefix_length);
176		(void) fprintf(fp, "via %s metric %d",
177		    inet_ntop(AF_INET6, (void *)&rt->rt_router, buf1,
178			sizeof (buf1)),
179		    rt->rt_metric);
180		if (rt->rt_ifp != NULL) {
181			(void) fprintf(fp, " if %s",
182			    (rt->rt_ifp->int_name != NULL) ?
183				rt->rt_ifp->int_name : "(noname)");
184		}
185		(void) fprintf(fp, " state");
186		c = ' ';
187		for (first = _B_TRUE, p = statebits; p->t_bits > 0; p++) {
188			if ((rt->rt_state & p->t_bits) == 0)
189				continue;
190			(void) fprintf(fp, "%c%s", c, p->t_name);
191			if (first) {
192				c = '|';
193				first = _B_FALSE;
194			}
195		}
196		if (first)
197			(void) fprintf(fp, " 0");
198		if (rt->rt_flags & (RTF_UP | RTF_GATEWAY)) {
199			c = ' ';
200			for (first = _B_TRUE, p = flagbits; p->t_bits > 0;
201			    p++) {
202				if ((rt->rt_flags & p->t_bits) == 0)
203					continue;
204				(void) fprintf(fp, "%c%s", c, p->t_name);
205				if (first) {
206					c = '|';
207					first = _B_FALSE;
208				}
209			}
210		}
211	}
212	(void) putc('\n', fp);
213	if (!tracepackets && rt != NULL && rt->rt_ifp != NULL)
214		dumpif(fp, rt->rt_ifp);
215	(void) fflush(fp);
216}
217
218static void
219dumpif(FILE *fp, struct interface *ifp)
220{
221	if (ifp->int_input.ifd_count != 0 || ifp->int_output.ifd_count != 0) {
222		(void) fprintf(fp, "*** Packet history for interface %s ***\n",
223		    (ifp->int_name != NULL) ? ifp->int_name : "(noname)");
224		dumptrace(fp, "to", &ifp->int_output);
225		dumptrace(fp, "from", &ifp->int_input);
226		(void) fprintf(fp, "*** end packet history ***\n");
227	}
228	(void) fflush(fp);
229}
230
231static void
232dumptrace(FILE *fp, char *dir, struct ifdebug *ifd)
233{
234	struct iftrace *t;
235	char *cp = (strcmp(dir, "to") != 0) ? "Output" : "Input";
236
237	if (ifd->ifd_front == ifd->ifd_records &&
238	    ifd->ifd_front->ift_size == 0) {
239		(void) fprintf(fp, "%s: no packets.\n", cp);
240		(void) fflush(fp);
241		return;
242	}
243	(void) fprintf(fp, "%s trace:\n", cp);
244	t = ifd->ifd_front - ifd->ifd_count;
245	if (t < ifd->ifd_records)
246		t += NRECORDS;
247	for (; ifd->ifd_count; ifd->ifd_count--, t++) {
248		if (t >= ifd->ifd_records + NRECORDS)
249			t = ifd->ifd_records;
250		if (t->ift_size == 0)
251			continue;
252		(void) fprintf(fp, "%.24s: metric=%d\n", ctime(&t->ift_stamp),
253		    t->ift_metric);
254		dumppacket(fp, dir, (struct sockaddr_in6 *)&t->ift_who,
255		    t->ift_packet, t->ift_size);
256	}
257}
258
259/*ARGSUSED*/
260void
261dumppacket(FILE *fp, char *dir, struct sockaddr_in6 *who, char *cp, int size)
262{
263	/* XXX Output contents of the RIP packet */
264}
265