1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate /*
31*0Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
32*0Sstevel@tonic-gate  * under license from the Regents of the University of California.
33*0Sstevel@tonic-gate  */
34*0Sstevel@tonic-gate 
35*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate /*
38*0Sstevel@tonic-gate  * Routing Table Management Daemon
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate #include "defs.h"
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate boolean_t	install = _B_TRUE;	/* update kernel routing table */
43*0Sstevel@tonic-gate struct rthash	*net_hashes[IPV6_ABITS + 1];
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate /*
46*0Sstevel@tonic-gate  * Size of routing socket message used by in.ripngd which includes the header,
47*0Sstevel@tonic-gate  * space for the RTA_DST, RTA_GATEWAY and RTA_NETMASK (each a sockaddr_in6)
48*0Sstevel@tonic-gate  * plus space for the RTA_IFP (a sockaddr_dl).
49*0Sstevel@tonic-gate  */
50*0Sstevel@tonic-gate #define	RIPNG_RTM_MSGLEN	sizeof (struct rt_msghdr) +	\
51*0Sstevel@tonic-gate 				sizeof (struct sockaddr_in6) +	\
52*0Sstevel@tonic-gate 				sizeof (struct sockaddr_in6) +	\
53*0Sstevel@tonic-gate 				sizeof (struct sockaddr_in6) +	\
54*0Sstevel@tonic-gate 				sizeof (struct sockaddr_dl)
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate static int	rtmseq;				/* rtm_seq sequence number */
57*0Sstevel@tonic-gate static int	rtsock;				/* Routing socket */
58*0Sstevel@tonic-gate static struct	rt_msghdr	*rt_msg;	/* Routing socket message */
59*0Sstevel@tonic-gate static struct	sockaddr_in6	*rta_dst;	/* RTA_DST sockaddr */
60*0Sstevel@tonic-gate static struct	sockaddr_in6	*rta_gateway;	/* RTA_GATEWAY sockaddr */
61*0Sstevel@tonic-gate static struct	sockaddr_in6	*rta_netmask;	/* RTA_NETMASK sockaddr */
62*0Sstevel@tonic-gate static struct	sockaddr_dl	*rta_ifp;	/* RTA_IFP sockaddr */
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate /* simulate vax insque and remque instructions. */
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate typedef struct vq {
67*0Sstevel@tonic-gate 	caddr_t	 fwd, back;
68*0Sstevel@tonic-gate } vq_t;
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate #define	insque(e, p)	((vq_t *)(e))->back = (caddr_t)(p); \
71*0Sstevel@tonic-gate 			((vq_t *)(e))->fwd = \
72*0Sstevel@tonic-gate 				(caddr_t)((vq_t *)((vq_t *)(p))->fwd); \
73*0Sstevel@tonic-gate 			((vq_t *)((vq_t *)(p))->fwd)->back = (caddr_t)(e); \
74*0Sstevel@tonic-gate 			((vq_t *)(p))->fwd = (caddr_t)(e);
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate #define	remque(e)	((vq_t *)((vq_t *)(e))->back)->fwd =  \
77*0Sstevel@tonic-gate 				(caddr_t)((vq_t *)(e))->fwd; \
78*0Sstevel@tonic-gate 			((vq_t *)((vq_t *)(e))->fwd)->back = \
79*0Sstevel@tonic-gate 				(caddr_t)((vq_t *)(e))->back; \
80*0Sstevel@tonic-gate 			((vq_t *)(e))->fwd = NULL; \
81*0Sstevel@tonic-gate 			((vq_t *)(e))->back = NULL;
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate static void
84*0Sstevel@tonic-gate log_change(int level, struct rt_entry *orig, struct rt_entry *new)
85*0Sstevel@tonic-gate {
86*0Sstevel@tonic-gate 	char buf1[INET6_ADDRSTRLEN];
87*0Sstevel@tonic-gate 	char buf2[INET6_ADDRSTRLEN];
88*0Sstevel@tonic-gate 	char buf3[INET6_ADDRSTRLEN];
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate 	(void) inet_ntop(AF_INET6, (void *) &new->rt_dst, buf1, sizeof (buf1));
91*0Sstevel@tonic-gate 	(void) inet_ntop(AF_INET6, (void *) &orig->rt_router, buf2,
92*0Sstevel@tonic-gate 	    sizeof (buf2));
93*0Sstevel@tonic-gate 	(void) inet_ntop(AF_INET6, (void *) &new->rt_router, buf3,
94*0Sstevel@tonic-gate 	    sizeof (buf3));
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 	syslog(level, "\tdst %s from gw %s if %s to gw %s if %s metric %d",
97*0Sstevel@tonic-gate 	    buf1, buf2,
98*0Sstevel@tonic-gate 	    (orig->rt_ifp != NULL && orig->rt_ifp->int_name != NULL) ?
99*0Sstevel@tonic-gate 		orig->rt_ifp->int_name : "(noname)",
100*0Sstevel@tonic-gate 	    buf3,
101*0Sstevel@tonic-gate 	    (new->rt_ifp != NULL && new->rt_ifp->int_name != NULL) ?
102*0Sstevel@tonic-gate 		new->rt_ifp->int_name : "(noname)", new->rt_metric);
103*0Sstevel@tonic-gate }
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate static void
106*0Sstevel@tonic-gate log_single(int level, struct rt_entry *rt)
107*0Sstevel@tonic-gate {
108*0Sstevel@tonic-gate 	char buf1[INET6_ADDRSTRLEN];
109*0Sstevel@tonic-gate 	char buf2[INET6_ADDRSTRLEN];
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	(void) inet_ntop(AF_INET6, (void *)&rt->rt_dst, buf1, sizeof (buf1));
112*0Sstevel@tonic-gate 	(void) inet_ntop(AF_INET6, (void *)&rt->rt_router, buf2, sizeof (buf2));
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate 	syslog(level, "\tdst %s gw %s if %s metric %d",
115*0Sstevel@tonic-gate 	    buf1, buf2,
116*0Sstevel@tonic-gate 	    (rt->rt_ifp != NULL && rt->rt_ifp->int_name != NULL) ?
117*0Sstevel@tonic-gate 		rt->rt_ifp->int_name : "(noname)",
118*0Sstevel@tonic-gate 	    rt->rt_metric);
119*0Sstevel@tonic-gate }
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate /*
122*0Sstevel@tonic-gate  * Computes a hash by XOR-ing the (up to sixteen) octets that make up an IPv6
123*0Sstevel@tonic-gate  * address.  This function assumes that that there are no one-bits in the
124*0Sstevel@tonic-gate  * address beyond the prefix length.
125*0Sstevel@tonic-gate  */
126*0Sstevel@tonic-gate static uint8_t
127*0Sstevel@tonic-gate rthash(struct in6_addr *dst, int prefix_length)
128*0Sstevel@tonic-gate {
129*0Sstevel@tonic-gate 	uint8_t val = 0;
130*0Sstevel@tonic-gate 	int i;
131*0Sstevel@tonic-gate 
132*0Sstevel@tonic-gate 	for (i = 0; prefix_length > 0; prefix_length -= 8, i++)
133*0Sstevel@tonic-gate 		val ^= dst->s6_addr[i];
134*0Sstevel@tonic-gate 	return (val);
135*0Sstevel@tonic-gate }
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate /*
138*0Sstevel@tonic-gate  * Given a prefix length, fill in the struct in6_addr representing an IPv6
139*0Sstevel@tonic-gate  * netmask.
140*0Sstevel@tonic-gate  */
141*0Sstevel@tonic-gate static void
142*0Sstevel@tonic-gate rtmask_to_bits(uint_t prefix_length, struct in6_addr *prefix)
143*0Sstevel@tonic-gate {
144*0Sstevel@tonic-gate 	uint_t mask = 0xff;
145*0Sstevel@tonic-gate 	int i;
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	bzero((caddr_t)prefix, sizeof (struct in6_addr));
148*0Sstevel@tonic-gate 	for (i = 0; prefix_length >= 8; prefix_length -= 8, i++)
149*0Sstevel@tonic-gate 		prefix->s6_addr[i] = 0xff;
150*0Sstevel@tonic-gate 	mask = (mask << (8 - prefix_length));
151*0Sstevel@tonic-gate 	if (mask != 0)
152*0Sstevel@tonic-gate 		prefix->s6_addr[i] = mask;
153*0Sstevel@tonic-gate }
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate void
156*0Sstevel@tonic-gate rtcreate_prefix(struct in6_addr *p1, struct in6_addr *dst, int bits)
157*0Sstevel@tonic-gate {
158*0Sstevel@tonic-gate 	uchar_t mask;
159*0Sstevel@tonic-gate 	int j;
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	for (j = 0; bits >= 8; bits -= 8, j++)
162*0Sstevel@tonic-gate 		dst->s6_addr[j] = p1->s6_addr[j];
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 	if (bits != 0) {
165*0Sstevel@tonic-gate 		mask = 0xff << (8 - bits);
166*0Sstevel@tonic-gate 		dst->s6_addr[j] = p1->s6_addr[j] & mask;
167*0Sstevel@tonic-gate 		j++;
168*0Sstevel@tonic-gate 	}
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate 	for (; j < 16; j++)
171*0Sstevel@tonic-gate 		dst->s6_addr[j] = 0;
172*0Sstevel@tonic-gate }
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate /*
175*0Sstevel@tonic-gate  * Lookup dst in the tables for an exact match.
176*0Sstevel@tonic-gate  */
177*0Sstevel@tonic-gate struct rt_entry *
178*0Sstevel@tonic-gate rtlookup(struct in6_addr *dst, int prefix_length)
179*0Sstevel@tonic-gate {
180*0Sstevel@tonic-gate 	struct rt_entry *rt;
181*0Sstevel@tonic-gate 	struct rthash *rh;
182*0Sstevel@tonic-gate 	uint_t	hash;
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	if (net_hashes[prefix_length] == NULL)
185*0Sstevel@tonic-gate 		return (NULL);
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	hash = rthash(dst, prefix_length);
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 	rh = &net_hashes[prefix_length][hash & ROUTEHASHMASK];
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 	for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
192*0Sstevel@tonic-gate 		if (rt->rt_hash != hash)
193*0Sstevel@tonic-gate 			continue;
194*0Sstevel@tonic-gate 		if (IN6_ARE_ADDR_EQUAL(&rt->rt_dst, dst) &&
195*0Sstevel@tonic-gate 		    rt->rt_prefix_length == prefix_length)
196*0Sstevel@tonic-gate 			return (rt);
197*0Sstevel@tonic-gate 	}
198*0Sstevel@tonic-gate 	return (NULL);
199*0Sstevel@tonic-gate }
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate /*
202*0Sstevel@tonic-gate  * Given an IPv6 prefix (destination and prefix length), a gateway, an
203*0Sstevel@tonic-gate  * interface name and route flags, send down the requested command returning
204*0Sstevel@tonic-gate  * the return value and errno (in the case of error) from the write() on the
205*0Sstevel@tonic-gate  * routing socket.
206*0Sstevel@tonic-gate  */
207*0Sstevel@tonic-gate static int
208*0Sstevel@tonic-gate rtcmd(uchar_t type, struct in6_addr *dst, struct in6_addr *gateway,
209*0Sstevel@tonic-gate     uint_t prefix_length, char *name, int flags)
210*0Sstevel@tonic-gate {
211*0Sstevel@tonic-gate 	int rlen;
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	rta_ifp->sdl_index = if_nametoindex(name);
214*0Sstevel@tonic-gate 	if (rta_ifp->sdl_index == 0)
215*0Sstevel@tonic-gate 		return (-1);
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	rta_dst->sin6_addr = *dst;
218*0Sstevel@tonic-gate 	rta_gateway->sin6_addr = *gateway;
219*0Sstevel@tonic-gate 	rtmask_to_bits(prefix_length, &rta_netmask->sin6_addr);
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	rt_msg->rtm_type = type;
222*0Sstevel@tonic-gate 	rt_msg->rtm_flags = flags;
223*0Sstevel@tonic-gate 	rt_msg->rtm_seq = ++rtmseq;
224*0Sstevel@tonic-gate 	rlen = write(rtsock, rt_msg, RIPNG_RTM_MSGLEN);
225*0Sstevel@tonic-gate 	if (rlen >= 0 && rlen < RIPNG_RTM_MSGLEN) {
226*0Sstevel@tonic-gate 		syslog(LOG_ERR,
227*0Sstevel@tonic-gate 		    "rtcmd: write to routing socket got only %d for rlen\n",
228*0Sstevel@tonic-gate 		    rlen);
229*0Sstevel@tonic-gate 	}
230*0Sstevel@tonic-gate 	return (rlen);
231*0Sstevel@tonic-gate }
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate void
234*0Sstevel@tonic-gate rtadd(struct in6_addr *dst, struct in6_addr *gate, int prefix_length,
235*0Sstevel@tonic-gate     int metric, int tag, boolean_t ifroute, struct interface *ifp)
236*0Sstevel@tonic-gate {
237*0Sstevel@tonic-gate 	struct rt_entry *rt;
238*0Sstevel@tonic-gate 	struct rthash *rh;
239*0Sstevel@tonic-gate 	uint_t hash;
240*0Sstevel@tonic-gate 	struct in6_addr pdst;
241*0Sstevel@tonic-gate 	int rlen;
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	if (metric >= HOPCNT_INFINITY)
244*0Sstevel@tonic-gate 		return;
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate 	if (net_hashes[prefix_length] == NULL) {
247*0Sstevel@tonic-gate 		struct rthash *trh;
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 		rh = (struct rthash *)
250*0Sstevel@tonic-gate 		    calloc(ROUTEHASHSIZ, sizeof (struct rt_entry));
251*0Sstevel@tonic-gate 		if (rh == NULL)
252*0Sstevel@tonic-gate 			return;
253*0Sstevel@tonic-gate 		for (trh = rh; trh < &rh[ROUTEHASHSIZ]; trh++)
254*0Sstevel@tonic-gate 			trh->rt_forw = trh->rt_back = (struct rt_entry *)trh;
255*0Sstevel@tonic-gate 		net_hashes[prefix_length] = rh;
256*0Sstevel@tonic-gate 	}
257*0Sstevel@tonic-gate 	rtcreate_prefix(dst, &pdst, prefix_length);
258*0Sstevel@tonic-gate 
259*0Sstevel@tonic-gate 	hash = rthash(&pdst, prefix_length);
260*0Sstevel@tonic-gate 	rh = &net_hashes[prefix_length][hash & ROUTEHASHMASK];
261*0Sstevel@tonic-gate 	rt = (struct rt_entry *)malloc(sizeof (*rt));
262*0Sstevel@tonic-gate 	if (rt == NULL) {
263*0Sstevel@tonic-gate 		/*
264*0Sstevel@tonic-gate 		 * In the event of an allocation failure, log the error and
265*0Sstevel@tonic-gate 		 * continue since on the next update another attempt will be
266*0Sstevel@tonic-gate 		 * made.
267*0Sstevel@tonic-gate 		 */
268*0Sstevel@tonic-gate 		syslog(LOG_ERR, "rtadd: malloc: %m");
269*0Sstevel@tonic-gate 		return;
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 	rt->rt_hash = hash;
272*0Sstevel@tonic-gate 	rt->rt_dst = pdst;
273*0Sstevel@tonic-gate 	rt->rt_prefix_length = prefix_length;
274*0Sstevel@tonic-gate 	rt->rt_router = *gate;
275*0Sstevel@tonic-gate 	rt->rt_metric = metric;
276*0Sstevel@tonic-gate 	rt->rt_tag = tag;
277*0Sstevel@tonic-gate 	rt->rt_timer = 0;
278*0Sstevel@tonic-gate 	rt->rt_flags = RTF_UP;
279*0Sstevel@tonic-gate 	if (prefix_length == IPV6_ABITS)
280*0Sstevel@tonic-gate 		rt->rt_flags |= RTF_HOST;
281*0Sstevel@tonic-gate 	rt->rt_state = RTS_CHANGED;
282*0Sstevel@tonic-gate 	if (ifroute) {
283*0Sstevel@tonic-gate 		rt->rt_state |= RTS_INTERFACE;
284*0Sstevel@tonic-gate 		if (ifp->int_flags & RIP6_IFF_PRIVATE)
285*0Sstevel@tonic-gate 			rt->rt_state |= RTS_PRIVATE;
286*0Sstevel@tonic-gate 	} else {
287*0Sstevel@tonic-gate 		rt->rt_flags |= RTF_GATEWAY;
288*0Sstevel@tonic-gate 	}
289*0Sstevel@tonic-gate 	rt->rt_ifp = ifp;
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	insque(rt, rh);
292*0Sstevel@tonic-gate 	TRACE_ACTION("ADD", rt);
293*0Sstevel@tonic-gate 	/*
294*0Sstevel@tonic-gate 	 * If the RTM_ADD fails because the gateway is unreachable
295*0Sstevel@tonic-gate 	 * from this host, discard the entry.  This should never
296*0Sstevel@tonic-gate 	 * happen.
297*0Sstevel@tonic-gate 	 */
298*0Sstevel@tonic-gate 	if (install && (rt->rt_state & RTS_INTERFACE) == 0) {
299*0Sstevel@tonic-gate 		rlen = rtcmd(RTM_ADD, &rt->rt_dst, &rt->rt_router,
300*0Sstevel@tonic-gate 		    prefix_length, ifp->int_name, rt->rt_flags);
301*0Sstevel@tonic-gate 		if (rlen < 0) {
302*0Sstevel@tonic-gate 			if (errno != EEXIST) {
303*0Sstevel@tonic-gate 				syslog(LOG_ERR, "rtadd: RTM_ADD: %m");
304*0Sstevel@tonic-gate 				log_single(LOG_ERR, rt);
305*0Sstevel@tonic-gate 			}
306*0Sstevel@tonic-gate 			if (errno == ENETUNREACH) {
307*0Sstevel@tonic-gate 				TRACE_ACTION("DELETE", rt);
308*0Sstevel@tonic-gate 				remque(rt);
309*0Sstevel@tonic-gate 				free((char *)rt);
310*0Sstevel@tonic-gate 			}
311*0Sstevel@tonic-gate 		} else if (rlen < RIPNG_RTM_MSGLEN) {
312*0Sstevel@tonic-gate 			log_single(LOG_ERR, rt);
313*0Sstevel@tonic-gate 		}
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate }
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate /*
318*0Sstevel@tonic-gate  * Handle the case when the metric changes but the gateway is the same (or the
319*0Sstevel@tonic-gate  * interface index associated with the gateway changes), or when both gateway
320*0Sstevel@tonic-gate  * and metric changes, or when only the gateway changes but the existing route
321*0Sstevel@tonic-gate  * is more than one-half of EXPIRE_TIME in age. Note that routes with metric >=
322*0Sstevel@tonic-gate  * HOPCNT_INFINITY are not in the kernel.
323*0Sstevel@tonic-gate  */
324*0Sstevel@tonic-gate void
325*0Sstevel@tonic-gate rtchange(struct rt_entry *rt, struct in6_addr *gate, short metric,
326*0Sstevel@tonic-gate     struct interface *ifp)
327*0Sstevel@tonic-gate {
328*0Sstevel@tonic-gate 	boolean_t dokern = _B_FALSE;
329*0Sstevel@tonic-gate 	boolean_t dokerndelete;
330*0Sstevel@tonic-gate 	boolean_t metricchanged = _B_FALSE;
331*0Sstevel@tonic-gate 	int oldmetric;
332*0Sstevel@tonic-gate 	struct rt_entry oldroute;
333*0Sstevel@tonic-gate 	int rlen;
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	if (metric >= HOPCNT_INFINITY) {
336*0Sstevel@tonic-gate 		rtdown(rt);
337*0Sstevel@tonic-gate 		return;
338*0Sstevel@tonic-gate 	}
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	if (!IN6_ARE_ADDR_EQUAL(&rt->rt_router, gate) || rt->rt_ifp != ifp)
341*0Sstevel@tonic-gate 		dokern = _B_TRUE;
342*0Sstevel@tonic-gate 	oldmetric = rt->rt_metric;
343*0Sstevel@tonic-gate 	if (oldmetric >= HOPCNT_INFINITY)
344*0Sstevel@tonic-gate 		dokerndelete = _B_FALSE;
345*0Sstevel@tonic-gate 	else
346*0Sstevel@tonic-gate 		dokerndelete = dokern;
347*0Sstevel@tonic-gate 	if (metric != rt->rt_metric)
348*0Sstevel@tonic-gate 		metricchanged = _B_TRUE;
349*0Sstevel@tonic-gate 	rt->rt_timer = 0;
350*0Sstevel@tonic-gate 	if (dokern || metricchanged) {
351*0Sstevel@tonic-gate 		TRACE_ACTION("CHANGE FROM", rt);
352*0Sstevel@tonic-gate 		if ((rt->rt_state & RTS_INTERFACE) && metric != 0) {
353*0Sstevel@tonic-gate 			rt->rt_state &= ~RTS_INTERFACE;
354*0Sstevel@tonic-gate 			if (rt->rt_ifp != NULL) {
355*0Sstevel@tonic-gate 				syslog(LOG_ERR,
356*0Sstevel@tonic-gate 				    "rtchange: changing route from "
357*0Sstevel@tonic-gate 				    "interface %s (timed out)",
358*0Sstevel@tonic-gate 				    (rt->rt_ifp->int_name != NULL) ?
359*0Sstevel@tonic-gate 					rt->rt_ifp->int_name : "(noname)");
360*0Sstevel@tonic-gate 			} else {
361*0Sstevel@tonic-gate 				syslog(LOG_ERR,
362*0Sstevel@tonic-gate 				    "rtchange: "
363*0Sstevel@tonic-gate 				    "changing route no interface for route");
364*0Sstevel@tonic-gate 			}
365*0Sstevel@tonic-gate 		}
366*0Sstevel@tonic-gate 		if (dokern) {
367*0Sstevel@tonic-gate 			oldroute = *rt;
368*0Sstevel@tonic-gate 			rt->rt_router = *gate;
369*0Sstevel@tonic-gate 			rt->rt_ifp = ifp;
370*0Sstevel@tonic-gate 		}
371*0Sstevel@tonic-gate 		rt->rt_metric = metric;
372*0Sstevel@tonic-gate 		if (!(rt->rt_state & RTS_INTERFACE))
373*0Sstevel@tonic-gate 			rt->rt_flags |= RTF_GATEWAY;
374*0Sstevel@tonic-gate 		else
375*0Sstevel@tonic-gate 			rt->rt_flags &= ~RTF_GATEWAY;
376*0Sstevel@tonic-gate 		rt->rt_state |= RTS_CHANGED;
377*0Sstevel@tonic-gate 		TRACE_ACTION("CHANGE TO", rt);
378*0Sstevel@tonic-gate 	}
379*0Sstevel@tonic-gate 	if (install && (rt->rt_state & RTS_INTERFACE) == 0) {
380*0Sstevel@tonic-gate 		if (dokerndelete) {
381*0Sstevel@tonic-gate 			rlen = rtcmd(RTM_ADD, &rt->rt_dst, &rt->rt_router,
382*0Sstevel@tonic-gate 			    rt->rt_prefix_length, rt->rt_ifp->int_name,
383*0Sstevel@tonic-gate 			    rt->rt_flags);
384*0Sstevel@tonic-gate 			if (rlen < 0) {
385*0Sstevel@tonic-gate 				if (errno != EEXIST) {
386*0Sstevel@tonic-gate 					syslog(LOG_ERR,
387*0Sstevel@tonic-gate 					    "rtchange: RTM_ADD: %m");
388*0Sstevel@tonic-gate 					log_change(LOG_ERR, rt,
389*0Sstevel@tonic-gate 					    (struct rt_entry *)&oldroute);
390*0Sstevel@tonic-gate 				}
391*0Sstevel@tonic-gate 			} else if (rlen < RIPNG_RTM_MSGLEN) {
392*0Sstevel@tonic-gate 				log_change(LOG_ERR, rt,
393*0Sstevel@tonic-gate 				    (struct rt_entry *)&oldroute);
394*0Sstevel@tonic-gate 			}
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 			rlen = rtcmd(RTM_DELETE, &oldroute.rt_dst,
397*0Sstevel@tonic-gate 			    &oldroute.rt_router, oldroute.rt_prefix_length,
398*0Sstevel@tonic-gate 			    oldroute.rt_ifp->int_name, oldroute.rt_flags);
399*0Sstevel@tonic-gate 			if (rlen < 0) {
400*0Sstevel@tonic-gate 				syslog(LOG_ERR, "rtchange: RTM_DELETE: %m");
401*0Sstevel@tonic-gate 				log_change(LOG_ERR, rt,
402*0Sstevel@tonic-gate 				    (struct rt_entry *)&oldroute);
403*0Sstevel@tonic-gate 			} else if (rlen < RIPNG_RTM_MSGLEN) {
404*0Sstevel@tonic-gate 				log_change(LOG_ERR, rt,
405*0Sstevel@tonic-gate 				    (struct rt_entry *)&oldroute);
406*0Sstevel@tonic-gate 			}
407*0Sstevel@tonic-gate 		} else if (dokern || oldmetric >= HOPCNT_INFINITY) {
408*0Sstevel@tonic-gate 			rlen = rtcmd(RTM_ADD, &rt->rt_dst, &rt->rt_router,
409*0Sstevel@tonic-gate 			    rt->rt_prefix_length, ifp->int_name, rt->rt_flags);
410*0Sstevel@tonic-gate 			if (rlen < 0 && errno != EEXIST) {
411*0Sstevel@tonic-gate 				syslog(LOG_ERR, "rtchange: RTM_ADD: %m");
412*0Sstevel@tonic-gate 				log_change(LOG_ERR, rt,
413*0Sstevel@tonic-gate 				    (struct rt_entry *)&oldroute);
414*0Sstevel@tonic-gate 			} else if (rlen < RIPNG_RTM_MSGLEN) {
415*0Sstevel@tonic-gate 				log_change(LOG_ERR, rt,
416*0Sstevel@tonic-gate 				    (struct rt_entry *)&oldroute);
417*0Sstevel@tonic-gate 			}
418*0Sstevel@tonic-gate 		}
419*0Sstevel@tonic-gate 	}
420*0Sstevel@tonic-gate }
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate void
423*0Sstevel@tonic-gate rtdown(struct rt_entry *rt)
424*0Sstevel@tonic-gate {
425*0Sstevel@tonic-gate 	int rlen;
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate 	if (rt->rt_metric != HOPCNT_INFINITY) {
428*0Sstevel@tonic-gate 		TRACE_ACTION("DELETE", rt);
429*0Sstevel@tonic-gate 		if (install && (rt->rt_state & RTS_INTERFACE) == 0) {
430*0Sstevel@tonic-gate 			rlen = rtcmd(RTM_DELETE, &rt->rt_dst,
431*0Sstevel@tonic-gate 			    &rt->rt_router, rt->rt_prefix_length,
432*0Sstevel@tonic-gate 			    rt->rt_ifp->int_name, rt->rt_flags);
433*0Sstevel@tonic-gate 			if (rlen < 0) {
434*0Sstevel@tonic-gate 				syslog(LOG_ERR, "rtdown: RTM_DELETE: %m");
435*0Sstevel@tonic-gate 				log_single(LOG_ERR, rt);
436*0Sstevel@tonic-gate 			} else if (rlen < RIPNG_RTM_MSGLEN) {
437*0Sstevel@tonic-gate 				log_single(LOG_ERR, rt);
438*0Sstevel@tonic-gate 			}
439*0Sstevel@tonic-gate 		}
440*0Sstevel@tonic-gate 		rt->rt_metric = HOPCNT_INFINITY;
441*0Sstevel@tonic-gate 		rt->rt_state |= RTS_CHANGED;
442*0Sstevel@tonic-gate 	}
443*0Sstevel@tonic-gate 	if (rt->rt_timer < EXPIRE_TIME)
444*0Sstevel@tonic-gate 		rt->rt_timer = EXPIRE_TIME;
445*0Sstevel@tonic-gate }
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate void
448*0Sstevel@tonic-gate rtdelete(struct rt_entry *rt)
449*0Sstevel@tonic-gate {
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	if (rt->rt_state & RTS_INTERFACE) {
452*0Sstevel@tonic-gate 		if (rt->rt_ifp != NULL) {
453*0Sstevel@tonic-gate 			syslog(LOG_ERR,
454*0Sstevel@tonic-gate 			    "rtdelete: "
455*0Sstevel@tonic-gate 			    "deleting route to interface %s (timed out)",
456*0Sstevel@tonic-gate 			    (rt->rt_ifp->int_name != NULL) ?
457*0Sstevel@tonic-gate 				rt->rt_ifp->int_name : "(noname)");
458*0Sstevel@tonic-gate 			log_single(LOG_ERR, rt);
459*0Sstevel@tonic-gate 		}
460*0Sstevel@tonic-gate 	}
461*0Sstevel@tonic-gate 	rtdown(rt);
462*0Sstevel@tonic-gate 	remque(rt);
463*0Sstevel@tonic-gate 	free((char *)rt);
464*0Sstevel@tonic-gate }
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate /*
467*0Sstevel@tonic-gate  * Mark all the routes heard off a particular interface "down".  Unlike the
468*0Sstevel@tonic-gate  * routes managed by in.routed, all of these routes have an interface associated
469*0Sstevel@tonic-gate  * with them.
470*0Sstevel@tonic-gate  */
471*0Sstevel@tonic-gate void
472*0Sstevel@tonic-gate rtpurgeif(struct interface *ifp)
473*0Sstevel@tonic-gate {
474*0Sstevel@tonic-gate 	struct rthash *rh;
475*0Sstevel@tonic-gate 	struct rt_entry *rt;
476*0Sstevel@tonic-gate 	int i;
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	for (i = IPV6_ABITS; i >= 0; i--) {
479*0Sstevel@tonic-gate 		if (net_hashes[i] == NULL)
480*0Sstevel@tonic-gate 			continue;
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 		for (rh = net_hashes[i];
483*0Sstevel@tonic-gate 		    rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) {
484*0Sstevel@tonic-gate 			for (rt = rh->rt_forw; rt != (struct rt_entry *)rh;
485*0Sstevel@tonic-gate 			    rt = rt->rt_forw) {
486*0Sstevel@tonic-gate 				if (rt->rt_ifp == ifp) {
487*0Sstevel@tonic-gate 					rtdown(rt);
488*0Sstevel@tonic-gate 					rt->rt_ifp = NULL;
489*0Sstevel@tonic-gate 					rt->rt_state &= ~RTS_INTERFACE;
490*0Sstevel@tonic-gate 				}
491*0Sstevel@tonic-gate 			}
492*0Sstevel@tonic-gate 		}
493*0Sstevel@tonic-gate 	}
494*0Sstevel@tonic-gate }
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate /*
497*0Sstevel@tonic-gate  * Called when the subnetmask has changed on one or more interfaces.
498*0Sstevel@tonic-gate  * Re-evaluates all non-interface routes by doing a rtchange so that
499*0Sstevel@tonic-gate  * routes that were believed to be host routes before the netmask change
500*0Sstevel@tonic-gate  * can be converted to network routes and vice versa.
501*0Sstevel@tonic-gate  */
502*0Sstevel@tonic-gate void
503*0Sstevel@tonic-gate rtchangeall(void)
504*0Sstevel@tonic-gate {
505*0Sstevel@tonic-gate 	struct rthash *rh;
506*0Sstevel@tonic-gate 	struct rt_entry *rt;
507*0Sstevel@tonic-gate 	int i;
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 	for (i = IPV6_ABITS; i >= 0; i--) {
510*0Sstevel@tonic-gate 		if (net_hashes[i] == NULL)
511*0Sstevel@tonic-gate 			continue;
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 		for (rh = net_hashes[i];
514*0Sstevel@tonic-gate 		    rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) {
515*0Sstevel@tonic-gate 			for (rt = rh->rt_forw; rt != (struct rt_entry *)rh;
516*0Sstevel@tonic-gate 			    rt = rt->rt_forw) {
517*0Sstevel@tonic-gate 				if ((rt->rt_state & RTS_INTERFACE) == 0) {
518*0Sstevel@tonic-gate 					rtchange(rt, &rt->rt_router,
519*0Sstevel@tonic-gate 					    rt->rt_metric, rt->rt_ifp);
520*0Sstevel@tonic-gate 				}
521*0Sstevel@tonic-gate 			}
522*0Sstevel@tonic-gate 		}
523*0Sstevel@tonic-gate 	}
524*0Sstevel@tonic-gate }
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate static void
527*0Sstevel@tonic-gate rtdumpentry(FILE *fp, struct rt_entry *rt)
528*0Sstevel@tonic-gate {
529*0Sstevel@tonic-gate 	char buf1[INET6_ADDRSTRLEN];
530*0Sstevel@tonic-gate 	static struct bits {
531*0Sstevel@tonic-gate 		ulong_t	t_bits;
532*0Sstevel@tonic-gate 		char	*t_name;
533*0Sstevel@tonic-gate 	} flagbits[] = {
534*0Sstevel@tonic-gate 		/* BEGIN CSTYLED */
535*0Sstevel@tonic-gate 		{ RTF_UP,		"UP" },
536*0Sstevel@tonic-gate 		{ RTF_GATEWAY,		"GATEWAY" },
537*0Sstevel@tonic-gate 		{ RTF_HOST,		"HOST" },
538*0Sstevel@tonic-gate 		{ 0,			NULL }
539*0Sstevel@tonic-gate 		/* END CSTYLED */
540*0Sstevel@tonic-gate 	}, statebits[] = {
541*0Sstevel@tonic-gate 		/* BEGIN CSTYLED */
542*0Sstevel@tonic-gate 		{ RTS_INTERFACE,	"INTERFACE" },
543*0Sstevel@tonic-gate 		{ RTS_CHANGED,		"CHANGED" },
544*0Sstevel@tonic-gate 		{ RTS_PRIVATE,		"PRIVATE" },
545*0Sstevel@tonic-gate 		{ 0,			NULL }
546*0Sstevel@tonic-gate 		/* END CSTYLED */
547*0Sstevel@tonic-gate 	};
548*0Sstevel@tonic-gate 	struct bits *p;
549*0Sstevel@tonic-gate 	boolean_t first;
550*0Sstevel@tonic-gate 	char c;
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate 	(void) fprintf(fp, "prefix %s/%d ",
553*0Sstevel@tonic-gate 	    inet_ntop(AF_INET6, (void *)&rt->rt_dst, buf1, sizeof (buf1)),
554*0Sstevel@tonic-gate 	    rt->rt_prefix_length);
555*0Sstevel@tonic-gate 	(void) fprintf(fp, "via %s metric %d timer %d",
556*0Sstevel@tonic-gate 	    inet_ntop(AF_INET6, (void *)&rt->rt_router, buf1, sizeof (buf1)),
557*0Sstevel@tonic-gate 	    rt->rt_metric, rt->rt_timer);
558*0Sstevel@tonic-gate 	if (rt->rt_ifp != NULL) {
559*0Sstevel@tonic-gate 		(void) fprintf(fp, " if %s",
560*0Sstevel@tonic-gate 		    (rt->rt_ifp->int_name != NULL) ?
561*0Sstevel@tonic-gate 			rt->rt_ifp->int_name : "(noname)");
562*0Sstevel@tonic-gate 	}
563*0Sstevel@tonic-gate 	(void) fprintf(fp, " state");
564*0Sstevel@tonic-gate 	c = ' ';
565*0Sstevel@tonic-gate 	for (first = _B_TRUE, p = statebits; p->t_bits > 0; p++) {
566*0Sstevel@tonic-gate 		if ((rt->rt_state & p->t_bits) == 0)
567*0Sstevel@tonic-gate 			continue;
568*0Sstevel@tonic-gate 		(void) fprintf(fp, "%c%s", c, p->t_name);
569*0Sstevel@tonic-gate 		if (first) {
570*0Sstevel@tonic-gate 			c = '|';
571*0Sstevel@tonic-gate 			first = _B_FALSE;
572*0Sstevel@tonic-gate 		}
573*0Sstevel@tonic-gate 	}
574*0Sstevel@tonic-gate 	if (first)
575*0Sstevel@tonic-gate 		(void) fprintf(fp, " 0");
576*0Sstevel@tonic-gate 	if (rt->rt_flags & (RTF_UP | RTF_GATEWAY)) {
577*0Sstevel@tonic-gate 		c = ' ';
578*0Sstevel@tonic-gate 		for (first = _B_TRUE, p = flagbits; p->t_bits > 0; p++) {
579*0Sstevel@tonic-gate 			if ((rt->rt_flags & p->t_bits) == 0)
580*0Sstevel@tonic-gate 				continue;
581*0Sstevel@tonic-gate 			(void) fprintf(fp, "%c%s", c, p->t_name);
582*0Sstevel@tonic-gate 			if (first) {
583*0Sstevel@tonic-gate 				c = '|';
584*0Sstevel@tonic-gate 				first = _B_FALSE;
585*0Sstevel@tonic-gate 			}
586*0Sstevel@tonic-gate 		}
587*0Sstevel@tonic-gate 	}
588*0Sstevel@tonic-gate 	(void) putc('\n', fp);
589*0Sstevel@tonic-gate 	(void) fflush(fp);
590*0Sstevel@tonic-gate }
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate static void
593*0Sstevel@tonic-gate rtdump2(FILE *fp)
594*0Sstevel@tonic-gate {
595*0Sstevel@tonic-gate 	struct rthash *rh;
596*0Sstevel@tonic-gate 	struct rt_entry *rt;
597*0Sstevel@tonic-gate 	int i;
598*0Sstevel@tonic-gate 
599*0Sstevel@tonic-gate 	for (i = IPV6_ABITS; i >= 0; i--) {
600*0Sstevel@tonic-gate 		if (net_hashes[i] == NULL)
601*0Sstevel@tonic-gate 			continue;
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 		for (rh = net_hashes[i];
604*0Sstevel@tonic-gate 		    rh < &net_hashes[i][ROUTEHASHSIZ]; rh++) {
605*0Sstevel@tonic-gate 			for (rt = rh->rt_forw; rt != (struct rt_entry *)rh;
606*0Sstevel@tonic-gate 			    rt = rt->rt_forw) {
607*0Sstevel@tonic-gate 				rtdumpentry(fp, rt);
608*0Sstevel@tonic-gate 			}
609*0Sstevel@tonic-gate 		}
610*0Sstevel@tonic-gate 	}
611*0Sstevel@tonic-gate }
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate void
614*0Sstevel@tonic-gate rtdump(void)
615*0Sstevel@tonic-gate {
616*0Sstevel@tonic-gate 	if (ftrace != NULL)
617*0Sstevel@tonic-gate 		rtdump2(ftrace);
618*0Sstevel@tonic-gate 	else
619*0Sstevel@tonic-gate 		rtdump2(stderr);
620*0Sstevel@tonic-gate }
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate /*
623*0Sstevel@tonic-gate  * Create a routing socket for sending RTM_ADD and RTM_DELETE messages and
624*0Sstevel@tonic-gate  * initialize the routing socket message header and as much of the sockaddrs
625*0Sstevel@tonic-gate  * as possible.
626*0Sstevel@tonic-gate  */
627*0Sstevel@tonic-gate void
628*0Sstevel@tonic-gate setup_rtsock(void)
629*0Sstevel@tonic-gate {
630*0Sstevel@tonic-gate 	char *cp;
631*0Sstevel@tonic-gate 	int off = 0;
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	rtsock = socket(PF_ROUTE, SOCK_RAW, AF_INET6);
634*0Sstevel@tonic-gate 	if (rtsock < 0) {
635*0Sstevel@tonic-gate 		syslog(LOG_ERR, "setup_rtsock: socket: %m");
636*0Sstevel@tonic-gate 		exit(EXIT_FAILURE);
637*0Sstevel@tonic-gate 	}
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate 	/* We don't want to listen to our own messages */
640*0Sstevel@tonic-gate 	if (setsockopt(rtsock, SOL_SOCKET, SO_USELOOPBACK, (char *)&off,
641*0Sstevel@tonic-gate 	    sizeof (off)) < 0) {
642*0Sstevel@tonic-gate 		syslog(LOG_ERR, "setup_rtsock: setsockopt: SO_USELOOPBACK: %m");
643*0Sstevel@tonic-gate 		exit(EXIT_FAILURE);
644*0Sstevel@tonic-gate 	}
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate 	/*
647*0Sstevel@tonic-gate 	 * Allocate storage for the routing socket message.
648*0Sstevel@tonic-gate 	 */
649*0Sstevel@tonic-gate 	rt_msg = (struct rt_msghdr *)malloc(RIPNG_RTM_MSGLEN);
650*0Sstevel@tonic-gate 	if (rt_msg == NULL) {
651*0Sstevel@tonic-gate 		syslog(LOG_ERR, "setup_rtsock: malloc: %m");
652*0Sstevel@tonic-gate 		exit(EXIT_FAILURE);
653*0Sstevel@tonic-gate 	}
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate 	/*
656*0Sstevel@tonic-gate 	 * Initialize the routing socket message by zero-filling it and then
657*0Sstevel@tonic-gate 	 * setting the fields where are constant through the lifetime of the
658*0Sstevel@tonic-gate 	 * process.
659*0Sstevel@tonic-gate 	 */
660*0Sstevel@tonic-gate 	bzero(rt_msg, RIPNG_RTM_MSGLEN);
661*0Sstevel@tonic-gate 	rt_msg->rtm_msglen = RIPNG_RTM_MSGLEN;
662*0Sstevel@tonic-gate 	rt_msg->rtm_version = RTM_VERSION;
663*0Sstevel@tonic-gate 	rt_msg->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP;
664*0Sstevel@tonic-gate 	rt_msg->rtm_pid = getpid();
665*0Sstevel@tonic-gate 	if (rt_msg->rtm_pid < 0) {
666*0Sstevel@tonic-gate 		syslog(LOG_ERR, "setup_rtsock: getpid: %m");
667*0Sstevel@tonic-gate 		exit(EXIT_FAILURE);
668*0Sstevel@tonic-gate 	}
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 	/*
671*0Sstevel@tonic-gate 	 * Initialize the constant portion of the RTA_DST sockaddr.
672*0Sstevel@tonic-gate 	 */
673*0Sstevel@tonic-gate 	cp = (char *)rt_msg + sizeof (struct rt_msghdr);
674*0Sstevel@tonic-gate 	rta_dst = (struct sockaddr_in6 *)cp;
675*0Sstevel@tonic-gate 	rta_dst->sin6_family = AF_INET6;
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 	/*
678*0Sstevel@tonic-gate 	 * Initialize the constant portion of the RTA_GATEWAY sockaddr.
679*0Sstevel@tonic-gate 	 */
680*0Sstevel@tonic-gate 	cp += sizeof (struct sockaddr_in6);
681*0Sstevel@tonic-gate 	rta_gateway = (struct sockaddr_in6 *)cp;
682*0Sstevel@tonic-gate 	rta_gateway->sin6_family = AF_INET6;
683*0Sstevel@tonic-gate 
684*0Sstevel@tonic-gate 	/*
685*0Sstevel@tonic-gate 	 * Initialize the constant portion of the RTA_NETMASK sockaddr.
686*0Sstevel@tonic-gate 	 */
687*0Sstevel@tonic-gate 	cp += sizeof (struct sockaddr_in6);
688*0Sstevel@tonic-gate 	rta_netmask = (struct sockaddr_in6 *)cp;
689*0Sstevel@tonic-gate 	rta_netmask->sin6_family = AF_INET6;
690*0Sstevel@tonic-gate 
691*0Sstevel@tonic-gate 	/*
692*0Sstevel@tonic-gate 	 * Initialize the constant portion of the RTA_IFP sockaddr.
693*0Sstevel@tonic-gate 	 */
694*0Sstevel@tonic-gate 	cp += sizeof (struct sockaddr_in6);
695*0Sstevel@tonic-gate 	rta_ifp = (struct sockaddr_dl *)cp;
696*0Sstevel@tonic-gate 	rta_ifp->sdl_family = AF_LINK;
697*0Sstevel@tonic-gate }
698