1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1999 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
32*7c478bd9Sstevel@tonic-gate  * under license from the Regents of the University of California.
33*7c478bd9Sstevel@tonic-gate  */
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate /*
36*7c478bd9Sstevel@tonic-gate  * Routing Table Management Daemon
37*7c478bd9Sstevel@tonic-gate  */
38*7c478bd9Sstevel@tonic-gate #include "defs.h"
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate static char	buf1[INET6_ADDRSTRLEN];
41*7c478bd9Sstevel@tonic-gate static char	buf2[INET6_ADDRSTRLEN];
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate static void	rip_input(struct sockaddr_in6 *from, int size, uint_t hopcount,
44*7c478bd9Sstevel@tonic-gate     struct interface *ifp);
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate /*
47*7c478bd9Sstevel@tonic-gate  * Return a pointer to the specified option buffer.
48*7c478bd9Sstevel@tonic-gate  * If not found return NULL.
49*7c478bd9Sstevel@tonic-gate  */
50*7c478bd9Sstevel@tonic-gate static void *
find_ancillary(struct msghdr * rmsg,int cmsg_type)51*7c478bd9Sstevel@tonic-gate find_ancillary(struct msghdr *rmsg, int cmsg_type)
52*7c478bd9Sstevel@tonic-gate {
53*7c478bd9Sstevel@tonic-gate 	struct cmsghdr *cmsg;
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate 	for (cmsg = CMSG_FIRSTHDR(rmsg); cmsg != NULL;
56*7c478bd9Sstevel@tonic-gate 	    cmsg = CMSG_NXTHDR(rmsg, cmsg)) {
57*7c478bd9Sstevel@tonic-gate 		if (cmsg->cmsg_level == IPPROTO_IPV6 &&
58*7c478bd9Sstevel@tonic-gate 		    cmsg->cmsg_type == cmsg_type) {
59*7c478bd9Sstevel@tonic-gate 			return (CMSG_DATA(cmsg));
60*7c478bd9Sstevel@tonic-gate 		}
61*7c478bd9Sstevel@tonic-gate 	}
62*7c478bd9Sstevel@tonic-gate 	return (NULL);
63*7c478bd9Sstevel@tonic-gate }
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate /*
66*7c478bd9Sstevel@tonic-gate  * Read a packet and passes it to rip_input() for processing.
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate void
in_data(struct interface * ifp)69*7c478bd9Sstevel@tonic-gate in_data(struct interface *ifp)
70*7c478bd9Sstevel@tonic-gate {
71*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 from;
72*7c478bd9Sstevel@tonic-gate 	int len;
73*7c478bd9Sstevel@tonic-gate 	struct msghdr rmsg;
74*7c478bd9Sstevel@tonic-gate 	struct iovec iov;
75*7c478bd9Sstevel@tonic-gate 	uchar_t *hopcntopt;
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate 	iov.iov_base = packet;
78*7c478bd9Sstevel@tonic-gate 	iov.iov_len = IPV6_MAX_PACKET;
79*7c478bd9Sstevel@tonic-gate 	rmsg.msg_name = &from;
80*7c478bd9Sstevel@tonic-gate 	rmsg.msg_namelen = (socklen_t)sizeof (from);
81*7c478bd9Sstevel@tonic-gate 	rmsg.msg_iov = &iov;
82*7c478bd9Sstevel@tonic-gate 	rmsg.msg_iovlen = 1;
83*7c478bd9Sstevel@tonic-gate 	rmsg.msg_control = control;
84*7c478bd9Sstevel@tonic-gate 	rmsg.msg_controllen = IPV6_MAX_PACKET;
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate 	if ((len = recvmsg(ifp->int_sock, &rmsg, 0)) < 0) {
87*7c478bd9Sstevel@tonic-gate 		/*
88*7c478bd9Sstevel@tonic-gate 		 * Only syslog if a true error occurred.
89*7c478bd9Sstevel@tonic-gate 		 */
90*7c478bd9Sstevel@tonic-gate 		if (errno != EINTR)
91*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "in_data: recvmsg: %m");
92*7c478bd9Sstevel@tonic-gate 		return;
93*7c478bd9Sstevel@tonic-gate 	}
94*7c478bd9Sstevel@tonic-gate 	if (len == 0)
95*7c478bd9Sstevel@tonic-gate 		return;
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate 	if (tracing & INPUT_BIT) {
98*7c478bd9Sstevel@tonic-gate 		(void) inet_ntop(from.sin6_family, &from.sin6_addr, buf1,
99*7c478bd9Sstevel@tonic-gate 		    sizeof (buf1));
100*7c478bd9Sstevel@tonic-gate 	}
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate 	/* Ignore packets > 64k or control buffers that don't fit */
103*7c478bd9Sstevel@tonic-gate 	if (rmsg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) {
104*7c478bd9Sstevel@tonic-gate 		if (tracing & INPUT_BIT) {
105*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
106*7c478bd9Sstevel@tonic-gate 			    "Truncated message: msg_flags 0x%x from %s\n",
107*7c478bd9Sstevel@tonic-gate 			    rmsg.msg_flags, buf1);
108*7c478bd9Sstevel@tonic-gate 		}
109*7c478bd9Sstevel@tonic-gate 		return;
110*7c478bd9Sstevel@tonic-gate 	}
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	if ((hopcntopt = find_ancillary(&rmsg, IPV6_HOPLIMIT)) == NULL) {
113*7c478bd9Sstevel@tonic-gate 		if (tracing & INPUT_BIT) {
114*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "Unknown hop limit from %s\n",
115*7c478bd9Sstevel@tonic-gate 			    buf1);
116*7c478bd9Sstevel@tonic-gate 		}
117*7c478bd9Sstevel@tonic-gate 		return;
118*7c478bd9Sstevel@tonic-gate 	}
119*7c478bd9Sstevel@tonic-gate 	rip_input(&from, len, *(uint_t *)hopcntopt, ifp);
120*7c478bd9Sstevel@tonic-gate }
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate /*
123*7c478bd9Sstevel@tonic-gate  * Process a newly received packet.
124*7c478bd9Sstevel@tonic-gate  */
125*7c478bd9Sstevel@tonic-gate static void
rip_input(struct sockaddr_in6 * from,int size,uint_t hopcount,struct interface * ifp)126*7c478bd9Sstevel@tonic-gate rip_input(struct sockaddr_in6 *from, int size, uint_t hopcount,
127*7c478bd9Sstevel@tonic-gate     struct interface *ifp)
128*7c478bd9Sstevel@tonic-gate {
129*7c478bd9Sstevel@tonic-gate 	struct rt_entry *rt;
130*7c478bd9Sstevel@tonic-gate 	struct netinfo6 *n;
131*7c478bd9Sstevel@tonic-gate 	int newsize;
132*7c478bd9Sstevel@tonic-gate 	boolean_t changes = _B_FALSE;
133*7c478bd9Sstevel@tonic-gate 	int answer = supplier;
134*7c478bd9Sstevel@tonic-gate 	struct in6_addr prefix;
135*7c478bd9Sstevel@tonic-gate 	struct in6_addr nexthop;
136*7c478bd9Sstevel@tonic-gate 	struct in6_addr *gate;
137*7c478bd9Sstevel@tonic-gate 	boolean_t foundnexthop = _B_FALSE;
138*7c478bd9Sstevel@tonic-gate 	struct sioc_addrreq sa;
139*7c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	TRACE_INPUT(ifp, from, size);
142*7c478bd9Sstevel@tonic-gate 	if (tracing & INPUT_BIT) {
143*7c478bd9Sstevel@tonic-gate 		(void) inet_ntop(from->sin6_family, (void *)&from->sin6_addr,
144*7c478bd9Sstevel@tonic-gate 		    buf1, sizeof (buf1));
145*7c478bd9Sstevel@tonic-gate 	}
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	/*
148*7c478bd9Sstevel@tonic-gate 	 * If the packet is recevied on an interface with IFF_NORTEXCH flag set,
149*7c478bd9Sstevel@tonic-gate 	 * we ignore the packet.
150*7c478bd9Sstevel@tonic-gate 	 */
151*7c478bd9Sstevel@tonic-gate 	if (ifp->int_flags & RIP6_IFF_NORTEXCH) {
152*7c478bd9Sstevel@tonic-gate 		if (tracing & INPUT_BIT) {
153*7c478bd9Sstevel@tonic-gate 			(void) fprintf(ftrace,
154*7c478bd9Sstevel@tonic-gate 			    "Ignore received RIPng packet on %s "
155*7c478bd9Sstevel@tonic-gate 			    "(no route exchange on interface)\n",
156*7c478bd9Sstevel@tonic-gate 			    ifp->int_name);
157*7c478bd9Sstevel@tonic-gate 			(void) fflush(ftrace);
158*7c478bd9Sstevel@tonic-gate 		}
159*7c478bd9Sstevel@tonic-gate 		return;
160*7c478bd9Sstevel@tonic-gate 	}
161*7c478bd9Sstevel@tonic-gate 	if (msg->rip6_vers != RIPVERSION6) {
162*7c478bd9Sstevel@tonic-gate 		if (tracing & INPUT_BIT) {
163*7c478bd9Sstevel@tonic-gate 			(void) fprintf(ftrace,
164*7c478bd9Sstevel@tonic-gate 			    "Bad version number %d in packet from %s\n",
165*7c478bd9Sstevel@tonic-gate 			    msg->rip6_vers, buf1);
166*7c478bd9Sstevel@tonic-gate 			(void) fflush(ftrace);
167*7c478bd9Sstevel@tonic-gate 		}
168*7c478bd9Sstevel@tonic-gate 		return;
169*7c478bd9Sstevel@tonic-gate 	}
170*7c478bd9Sstevel@tonic-gate 	if (ntohs(msg->rip6_res1) != 0) {
171*7c478bd9Sstevel@tonic-gate 		if (tracing & INPUT_BIT) {
172*7c478bd9Sstevel@tonic-gate 			(void) fprintf(ftrace,
173*7c478bd9Sstevel@tonic-gate 			    "Non-zero reserved octets found in packet from "
174*7c478bd9Sstevel@tonic-gate 			    "%s\n",
175*7c478bd9Sstevel@tonic-gate 			    buf1);
176*7c478bd9Sstevel@tonic-gate 			(void) fflush(ftrace);
177*7c478bd9Sstevel@tonic-gate 		}
178*7c478bd9Sstevel@tonic-gate 	}
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 	switch (msg->rip6_cmd) {
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	case RIPCMD6_REQUEST:		/* multicasted request */
183*7c478bd9Sstevel@tonic-gate 		ifp->int_ipackets++;
184*7c478bd9Sstevel@tonic-gate 		newsize = 0;
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 		/*
187*7c478bd9Sstevel@tonic-gate 		 * Adjust size by the length of the command, version and
188*7c478bd9Sstevel@tonic-gate 		 * reserved fields (which are in total 32-bit aligned).
189*7c478bd9Sstevel@tonic-gate 		 */
190*7c478bd9Sstevel@tonic-gate 		size -= sizeof (msg->rip6_cmd) + sizeof (msg->rip6_vers) +
191*7c478bd9Sstevel@tonic-gate 		    sizeof (msg->rip6_res1);
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 		/*
194*7c478bd9Sstevel@tonic-gate 		 * From section 2.4.1 of RFC 2080:
195*7c478bd9Sstevel@tonic-gate 		 *
196*7c478bd9Sstevel@tonic-gate 		 *	If there is exactly one entry in the request with a
197*7c478bd9Sstevel@tonic-gate 		 *	destination prefix of zero, a prefix length of zero and
198*7c478bd9Sstevel@tonic-gate 		 *	an infinite metric, then supply the entire routing
199*7c478bd9Sstevel@tonic-gate 		 *	table.
200*7c478bd9Sstevel@tonic-gate 		 */
201*7c478bd9Sstevel@tonic-gate 		n = msg->rip6_nets;
202*7c478bd9Sstevel@tonic-gate 		if (size == sizeof (struct netinfo6) &&
203*7c478bd9Sstevel@tonic-gate 		    n->rip6_prefix_length == 0 &&
204*7c478bd9Sstevel@tonic-gate 		    n->rip6_metric == HOPCNT_INFINITY) {
205*7c478bd9Sstevel@tonic-gate 			rtcreate_prefix(&n->rip6_prefix, &prefix,
206*7c478bd9Sstevel@tonic-gate 			    n->rip6_prefix_length);
207*7c478bd9Sstevel@tonic-gate 			if (IN6_IS_ADDR_UNSPECIFIED(&prefix)) {
208*7c478bd9Sstevel@tonic-gate 				supply(from, ifp, 0,
209*7c478bd9Sstevel@tonic-gate 				    from->sin6_port == rip6_port);
210*7c478bd9Sstevel@tonic-gate 				return;
211*7c478bd9Sstevel@tonic-gate 			}
212*7c478bd9Sstevel@tonic-gate 		}
213*7c478bd9Sstevel@tonic-gate 		for (; size >= sizeof (struct netinfo6);
214*7c478bd9Sstevel@tonic-gate 		    size -= sizeof (struct netinfo6), n++) {
215*7c478bd9Sstevel@tonic-gate 			if (n->rip6_prefix_length > IPV6_ABITS) {
216*7c478bd9Sstevel@tonic-gate 				if (tracing & INPUT_BIT) {
217*7c478bd9Sstevel@tonic-gate 					(void) fprintf(ftrace,
218*7c478bd9Sstevel@tonic-gate 					    "Bad prefix length %d in request "
219*7c478bd9Sstevel@tonic-gate 					    "from %s\n",
220*7c478bd9Sstevel@tonic-gate 					    n->rip6_prefix_length, buf1);
221*7c478bd9Sstevel@tonic-gate 					(void) fflush(ftrace);
222*7c478bd9Sstevel@tonic-gate 				}
223*7c478bd9Sstevel@tonic-gate 				continue;
224*7c478bd9Sstevel@tonic-gate 			}
225*7c478bd9Sstevel@tonic-gate 			if (IN6_IS_ADDR_LINKLOCAL(&n->rip6_prefix) ||
226*7c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_MULTICAST(&n->rip6_prefix)) {
227*7c478bd9Sstevel@tonic-gate 				if (tracing & INPUT_BIT) {
228*7c478bd9Sstevel@tonic-gate 					(void) fprintf(ftrace,
229*7c478bd9Sstevel@tonic-gate 					    "Bad prefix %s in request from "
230*7c478bd9Sstevel@tonic-gate 					    "%s\n",
231*7c478bd9Sstevel@tonic-gate 					    inet_ntop(AF_INET6,
232*7c478bd9Sstevel@tonic-gate 						(void *)&n->rip6_prefix, buf2,
233*7c478bd9Sstevel@tonic-gate 						sizeof (buf2)),
234*7c478bd9Sstevel@tonic-gate 					    buf1);
235*7c478bd9Sstevel@tonic-gate 					(void) fflush(ftrace);
236*7c478bd9Sstevel@tonic-gate 				}
237*7c478bd9Sstevel@tonic-gate 				continue;
238*7c478bd9Sstevel@tonic-gate 			}
239*7c478bd9Sstevel@tonic-gate 			rtcreate_prefix(&n->rip6_prefix, &prefix,
240*7c478bd9Sstevel@tonic-gate 			    n->rip6_prefix_length);
241*7c478bd9Sstevel@tonic-gate 			rt = rtlookup(&prefix, n->rip6_prefix_length);
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 			n->rip6_metric = (rt == NULL ?
244*7c478bd9Sstevel@tonic-gate 			    HOPCNT_INFINITY :
245*7c478bd9Sstevel@tonic-gate 			    min(rt->rt_metric, HOPCNT_INFINITY));
246*7c478bd9Sstevel@tonic-gate 			newsize += sizeof (struct netinfo6);
247*7c478bd9Sstevel@tonic-gate 		}
248*7c478bd9Sstevel@tonic-gate 		if (size > 0) {
249*7c478bd9Sstevel@tonic-gate 			if (tracing & INPUT_BIT) {
250*7c478bd9Sstevel@tonic-gate 				(void) fprintf(ftrace,
251*7c478bd9Sstevel@tonic-gate 				    "Ignoring %d octets of trailing data in "
252*7c478bd9Sstevel@tonic-gate 				    "request from %s\n",
253*7c478bd9Sstevel@tonic-gate 				    size, buf1);
254*7c478bd9Sstevel@tonic-gate 				(void) fflush(ftrace);
255*7c478bd9Sstevel@tonic-gate 			}
256*7c478bd9Sstevel@tonic-gate 		}
257*7c478bd9Sstevel@tonic-gate 		if (answer && newsize > 0) {
258*7c478bd9Sstevel@tonic-gate 			/*
259*7c478bd9Sstevel@tonic-gate 			 * Adjust newsize by the length of the command, version
260*7c478bd9Sstevel@tonic-gate 			 * and reserved fields (which are in total 32-bit
261*7c478bd9Sstevel@tonic-gate 			 * aligned).
262*7c478bd9Sstevel@tonic-gate 			 */
263*7c478bd9Sstevel@tonic-gate 			msg->rip6_cmd = RIPCMD6_RESPONSE;
264*7c478bd9Sstevel@tonic-gate 			newsize += sizeof (msg->rip6_cmd) +
265*7c478bd9Sstevel@tonic-gate 			    sizeof (msg->rip6_vers) + sizeof (msg->rip6_res1);
266*7c478bd9Sstevel@tonic-gate 			sendpacket(from, ifp, newsize, 0);
267*7c478bd9Sstevel@tonic-gate 		}
268*7c478bd9Sstevel@tonic-gate 		return;
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	case RIPCMD6_RESPONSE:
271*7c478bd9Sstevel@tonic-gate 		if (hopcount != IPV6_MAX_HOPS) {
272*7c478bd9Sstevel@tonic-gate 			if (tracing & INPUT_BIT) {
273*7c478bd9Sstevel@tonic-gate 				(void) fprintf(ftrace,
274*7c478bd9Sstevel@tonic-gate 				    "Bad hop count %d in response from %s\n",
275*7c478bd9Sstevel@tonic-gate 				    hopcount, buf1);
276*7c478bd9Sstevel@tonic-gate 				(void) fflush(ftrace);
277*7c478bd9Sstevel@tonic-gate 			}
278*7c478bd9Sstevel@tonic-gate 			return;
279*7c478bd9Sstevel@tonic-gate 		}
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 		if (from->sin6_port != rip6_port) {
282*7c478bd9Sstevel@tonic-gate 			if (tracing & INPUT_BIT) {
283*7c478bd9Sstevel@tonic-gate 				(void) fprintf(ftrace,
284*7c478bd9Sstevel@tonic-gate 				    "Bad source port %d in response from %s\n",
285*7c478bd9Sstevel@tonic-gate 				    from->sin6_port, buf1);
286*7c478bd9Sstevel@tonic-gate 				(void) fflush(ftrace);
287*7c478bd9Sstevel@tonic-gate 			}
288*7c478bd9Sstevel@tonic-gate 			return;
289*7c478bd9Sstevel@tonic-gate 		}
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 		if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
292*7c478bd9Sstevel@tonic-gate 			if (tracing & INPUT_BIT) {
293*7c478bd9Sstevel@tonic-gate 				(void) fprintf(ftrace,
294*7c478bd9Sstevel@tonic-gate 				    "Bad source address (not link-local) in "
295*7c478bd9Sstevel@tonic-gate 				    "response from %s\n", buf1);
296*7c478bd9Sstevel@tonic-gate 				(void) fflush(ftrace);
297*7c478bd9Sstevel@tonic-gate 			}
298*7c478bd9Sstevel@tonic-gate 			return;
299*7c478bd9Sstevel@tonic-gate 		}
300*7c478bd9Sstevel@tonic-gate 		ifp->int_ipackets++;
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 		/*
303*7c478bd9Sstevel@tonic-gate 		 * Adjust size by the length of the command, version and
304*7c478bd9Sstevel@tonic-gate 		 * reserved fields (which are in total 32-bit aligned).
305*7c478bd9Sstevel@tonic-gate 		 */
306*7c478bd9Sstevel@tonic-gate 		size -= sizeof (msg->rip6_cmd) + sizeof (msg->rip6_vers) +
307*7c478bd9Sstevel@tonic-gate 		    sizeof (msg->rip6_res1);
308*7c478bd9Sstevel@tonic-gate 		for (n = msg->rip6_nets;
309*7c478bd9Sstevel@tonic-gate 		    supplier && size >= sizeof (struct netinfo6);
310*7c478bd9Sstevel@tonic-gate 		    size -= sizeof (struct netinfo6), n++) {
311*7c478bd9Sstevel@tonic-gate 			/*
312*7c478bd9Sstevel@tonic-gate 			 * From section 2.1.1 of RFC 2080:
313*7c478bd9Sstevel@tonic-gate 			 *
314*7c478bd9Sstevel@tonic-gate 			 * This is a next hop RTE if n->rip6_metric is set to
315*7c478bd9Sstevel@tonic-gate 			 * HOPCNT_NEXTHOP.  If the next hop address (which is
316*7c478bd9Sstevel@tonic-gate 			 * placed in the prefix field of this special RTE) is
317*7c478bd9Sstevel@tonic-gate 			 * unspecified or is not a link-local address, then use
318*7c478bd9Sstevel@tonic-gate 			 * the originator's address instead (effectively turning
319*7c478bd9Sstevel@tonic-gate 			 * off next hop RTE processing.)
320*7c478bd9Sstevel@tonic-gate 			 */
321*7c478bd9Sstevel@tonic-gate 			if (n->rip6_metric == HOPCNT_NEXTHOP) {
322*7c478bd9Sstevel@tonic-gate 				/*
323*7c478bd9Sstevel@tonic-gate 				 * First check to see if the unspecified address
324*7c478bd9Sstevel@tonic-gate 				 * was given as the next hop address.  This is
325*7c478bd9Sstevel@tonic-gate 				 * the correct way of specifying the end of use
326*7c478bd9Sstevel@tonic-gate 				 * of a next hop address.
327*7c478bd9Sstevel@tonic-gate 				 */
328*7c478bd9Sstevel@tonic-gate 				if (IN6_IS_ADDR_UNSPECIFIED(&n->rip6_prefix)) {
329*7c478bd9Sstevel@tonic-gate 					foundnexthop = _B_FALSE;
330*7c478bd9Sstevel@tonic-gate 					continue;
331*7c478bd9Sstevel@tonic-gate 				}
332*7c478bd9Sstevel@tonic-gate 				/*
333*7c478bd9Sstevel@tonic-gate 				 * A next hop address that is not a link-local
334*7c478bd9Sstevel@tonic-gate 				 * address is treated as the unspecified one.
335*7c478bd9Sstevel@tonic-gate 				 * Trace this event if input tracing is enabled.
336*7c478bd9Sstevel@tonic-gate 				 */
337*7c478bd9Sstevel@tonic-gate 				if (!IN6_IS_ADDR_LINKLOCAL(&n->rip6_prefix)) {
338*7c478bd9Sstevel@tonic-gate 					foundnexthop = _B_FALSE;
339*7c478bd9Sstevel@tonic-gate 					if (tracing & INPUT_BIT) {
340*7c478bd9Sstevel@tonic-gate 						(void) fprintf(ftrace,
341*7c478bd9Sstevel@tonic-gate 						    "Bad next hop %s in "
342*7c478bd9Sstevel@tonic-gate 						    "response from %s\n",
343*7c478bd9Sstevel@tonic-gate 						    inet_ntop(AF_INET6,
344*7c478bd9Sstevel@tonic-gate 							(void *)&n->rip6_prefix,
345*7c478bd9Sstevel@tonic-gate 							buf2, sizeof (buf2)),
346*7c478bd9Sstevel@tonic-gate 						    buf1);
347*7c478bd9Sstevel@tonic-gate 					}
348*7c478bd9Sstevel@tonic-gate 					continue;
349*7c478bd9Sstevel@tonic-gate 				}
350*7c478bd9Sstevel@tonic-gate 				/*
351*7c478bd9Sstevel@tonic-gate 				 * Verify that the next hop address is not one
352*7c478bd9Sstevel@tonic-gate 				 * of our own.
353*7c478bd9Sstevel@tonic-gate 				 */
354*7c478bd9Sstevel@tonic-gate 				sin6 = (struct sockaddr_in6 *)&sa.sa_addr;
355*7c478bd9Sstevel@tonic-gate 				sin6->sin6_family = AF_INET6;
356*7c478bd9Sstevel@tonic-gate 				sin6->sin6_addr = n->rip6_prefix;
357*7c478bd9Sstevel@tonic-gate 				if (ioctl(iocsoc, SIOCTMYADDR,
358*7c478bd9Sstevel@tonic-gate 				    (char *)&sa) < 0) {
359*7c478bd9Sstevel@tonic-gate 					syslog(LOG_ERR,
360*7c478bd9Sstevel@tonic-gate 					    "rip_input: "
361*7c478bd9Sstevel@tonic-gate 					    "ioctl (verify my address): %m");
362*7c478bd9Sstevel@tonic-gate 					return;
363*7c478bd9Sstevel@tonic-gate 				}
364*7c478bd9Sstevel@tonic-gate 				if (sa.sa_res != 0) {
365*7c478bd9Sstevel@tonic-gate 					foundnexthop = _B_FALSE;
366*7c478bd9Sstevel@tonic-gate 					if (tracing & INPUT_BIT) {
367*7c478bd9Sstevel@tonic-gate 						(void) fprintf(ftrace,
368*7c478bd9Sstevel@tonic-gate 						    "Bad next hop %s is self "
369*7c478bd9Sstevel@tonic-gate 						    "in response from %s\n",
370*7c478bd9Sstevel@tonic-gate 						    inet_ntop(AF_INET6,
371*7c478bd9Sstevel@tonic-gate 							(void *)&n->rip6_prefix,
372*7c478bd9Sstevel@tonic-gate 							buf2, sizeof (buf2)),
373*7c478bd9Sstevel@tonic-gate 						    buf1);
374*7c478bd9Sstevel@tonic-gate 					}
375*7c478bd9Sstevel@tonic-gate 					continue;
376*7c478bd9Sstevel@tonic-gate 				}
377*7c478bd9Sstevel@tonic-gate 				foundnexthop = _B_TRUE;
378*7c478bd9Sstevel@tonic-gate 				nexthop = n->rip6_prefix;
379*7c478bd9Sstevel@tonic-gate 				continue;
380*7c478bd9Sstevel@tonic-gate 			}
381*7c478bd9Sstevel@tonic-gate 			if (foundnexthop)
382*7c478bd9Sstevel@tonic-gate 				gate = &nexthop;
383*7c478bd9Sstevel@tonic-gate 			else
384*7c478bd9Sstevel@tonic-gate 				gate = &from->sin6_addr;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 			if (n->rip6_metric > HOPCNT_INFINITY ||
387*7c478bd9Sstevel@tonic-gate 			    n->rip6_metric < 1) {
388*7c478bd9Sstevel@tonic-gate 				if (tracing & INPUT_BIT) {
389*7c478bd9Sstevel@tonic-gate 					(void) fprintf(ftrace,
390*7c478bd9Sstevel@tonic-gate 					    "Bad metric %d in response from "
391*7c478bd9Sstevel@tonic-gate 					    "%s\n",
392*7c478bd9Sstevel@tonic-gate 					    n->rip6_metric, buf1);
393*7c478bd9Sstevel@tonic-gate 					(void) fflush(ftrace);
394*7c478bd9Sstevel@tonic-gate 				}
395*7c478bd9Sstevel@tonic-gate 				continue;
396*7c478bd9Sstevel@tonic-gate 			}
397*7c478bd9Sstevel@tonic-gate 			if (n->rip6_prefix_length > IPV6_ABITS) {
398*7c478bd9Sstevel@tonic-gate 				if (tracing & INPUT_BIT) {
399*7c478bd9Sstevel@tonic-gate 					(void) fprintf(ftrace,
400*7c478bd9Sstevel@tonic-gate 					    "Bad prefix length %d in response "
401*7c478bd9Sstevel@tonic-gate 					    "from %s\n",
402*7c478bd9Sstevel@tonic-gate 					    n->rip6_prefix_length, buf1);
403*7c478bd9Sstevel@tonic-gate 					(void) fflush(ftrace);
404*7c478bd9Sstevel@tonic-gate 				}
405*7c478bd9Sstevel@tonic-gate 				continue;
406*7c478bd9Sstevel@tonic-gate 			}
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 			if (IN6_IS_ADDR_LINKLOCAL(&n->rip6_prefix) ||
409*7c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_MULTICAST(&n->rip6_prefix)) {
410*7c478bd9Sstevel@tonic-gate 				if (tracing & INPUT_BIT) {
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 					(void) fprintf(ftrace,
413*7c478bd9Sstevel@tonic-gate 					    "Bad prefix %s in response from "
414*7c478bd9Sstevel@tonic-gate 					    "%s\n",
415*7c478bd9Sstevel@tonic-gate 					    inet_ntop(AF_INET6,
416*7c478bd9Sstevel@tonic-gate 						(void *)&n->rip6_prefix, buf2,
417*7c478bd9Sstevel@tonic-gate 						sizeof (buf2)),
418*7c478bd9Sstevel@tonic-gate 					    buf1);
419*7c478bd9Sstevel@tonic-gate 					(void) fflush(ftrace);
420*7c478bd9Sstevel@tonic-gate 				}
421*7c478bd9Sstevel@tonic-gate 				continue;
422*7c478bd9Sstevel@tonic-gate 			}
423*7c478bd9Sstevel@tonic-gate 			/* Include metric for incoming interface */
424*7c478bd9Sstevel@tonic-gate 			n->rip6_metric += IFMETRIC(ifp);
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 			rtcreate_prefix(&n->rip6_prefix, &prefix,
427*7c478bd9Sstevel@tonic-gate 			    n->rip6_prefix_length);
428*7c478bd9Sstevel@tonic-gate 			rt = rtlookup(&prefix, n->rip6_prefix_length);
429*7c478bd9Sstevel@tonic-gate 			if (rt == NULL) {
430*7c478bd9Sstevel@tonic-gate 				if (n->rip6_metric < HOPCNT_INFINITY) {
431*7c478bd9Sstevel@tonic-gate 					rtadd(&prefix,
432*7c478bd9Sstevel@tonic-gate 					    gate, n->rip6_prefix_length,
433*7c478bd9Sstevel@tonic-gate 					    n->rip6_metric, n->rip6_route_tag,
434*7c478bd9Sstevel@tonic-gate 					    _B_FALSE, ifp);
435*7c478bd9Sstevel@tonic-gate 					changes = _B_TRUE;
436*7c478bd9Sstevel@tonic-gate 				}
437*7c478bd9Sstevel@tonic-gate 				continue;
438*7c478bd9Sstevel@tonic-gate 			}
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 			/*
441*7c478bd9Sstevel@tonic-gate 			 * If the supplied metric is at least HOPCNT_INFINITY
442*7c478bd9Sstevel@tonic-gate 			 * and the current metric of the route is
443*7c478bd9Sstevel@tonic-gate 			 * HOPCNT_INFINITY, then this particular RTE is ignored.
444*7c478bd9Sstevel@tonic-gate 			 */
445*7c478bd9Sstevel@tonic-gate 			if (n->rip6_metric >= HOPCNT_INFINITY &&
446*7c478bd9Sstevel@tonic-gate 			    rt->rt_metric == HOPCNT_INFINITY)
447*7c478bd9Sstevel@tonic-gate 				continue;
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 			/*
450*7c478bd9Sstevel@tonic-gate 			 * From section 2.4.2 of RFC 2080:
451*7c478bd9Sstevel@tonic-gate 			 *
452*7c478bd9Sstevel@tonic-gate 			 * Update if any one of the following is true
453*7c478bd9Sstevel@tonic-gate 			 *
454*7c478bd9Sstevel@tonic-gate 			 *	1) From current gateway and a different metric.
455*7c478bd9Sstevel@tonic-gate 			 *	2) From current gateway and a different index.
456*7c478bd9Sstevel@tonic-gate 			 *	3) A shorter (smaller) metric.
457*7c478bd9Sstevel@tonic-gate 			 *	4) Equivalent metric and an age at least
458*7c478bd9Sstevel@tonic-gate 			 *	   one-half of EXPIRE_TIME.
459*7c478bd9Sstevel@tonic-gate 			 *
460*7c478bd9Sstevel@tonic-gate 			 * Otherwise, update timer for the interface on which
461*7c478bd9Sstevel@tonic-gate 			 * the packet arrived.
462*7c478bd9Sstevel@tonic-gate 			 */
463*7c478bd9Sstevel@tonic-gate 			if (IN6_ARE_ADDR_EQUAL(gate, &rt->rt_router)) {
464*7c478bd9Sstevel@tonic-gate 				if (n->rip6_metric != rt->rt_metric ||
465*7c478bd9Sstevel@tonic-gate 				    rt->rt_ifp != ifp) {
466*7c478bd9Sstevel@tonic-gate 					rtchange(rt, gate, n->rip6_metric, ifp);
467*7c478bd9Sstevel@tonic-gate 					changes = _B_TRUE;
468*7c478bd9Sstevel@tonic-gate 				} else if (n->rip6_metric < HOPCNT_INFINITY) {
469*7c478bd9Sstevel@tonic-gate 					rt->rt_timer = 0;
470*7c478bd9Sstevel@tonic-gate 				}
471*7c478bd9Sstevel@tonic-gate 			} else if (n->rip6_metric < rt->rt_metric ||
472*7c478bd9Sstevel@tonic-gate 			    (rt->rt_timer > (EXPIRE_TIME / 2) &&
473*7c478bd9Sstevel@tonic-gate 				rt->rt_metric == n->rip6_metric)) {
474*7c478bd9Sstevel@tonic-gate 				rtchange(rt, gate, n->rip6_metric, ifp);
475*7c478bd9Sstevel@tonic-gate 				changes = _B_TRUE;
476*7c478bd9Sstevel@tonic-gate 			}
477*7c478bd9Sstevel@tonic-gate 		}
478*7c478bd9Sstevel@tonic-gate 		if (changes && supplier)
479*7c478bd9Sstevel@tonic-gate 			dynamic_update(ifp);
480*7c478bd9Sstevel@tonic-gate 		return;
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	default:
483*7c478bd9Sstevel@tonic-gate 		if (tracing & INPUT_BIT) {
484*7c478bd9Sstevel@tonic-gate 			(void) fprintf(ftrace,
485*7c478bd9Sstevel@tonic-gate 			    "Bad command %d in packet from %s\n",
486*7c478bd9Sstevel@tonic-gate 			    msg->rip6_cmd, buf1);
487*7c478bd9Sstevel@tonic-gate 			(void) fflush(ftrace);
488*7c478bd9Sstevel@tonic-gate 		}
489*7c478bd9Sstevel@tonic-gate 		return;
490*7c478bd9Sstevel@tonic-gate 	}
491*7c478bd9Sstevel@tonic-gate }
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate /*
494*7c478bd9Sstevel@tonic-gate  * If changes have occurred, and if we have not sent a multicast
495*7c478bd9Sstevel@tonic-gate  * recently, send a dynamic update.  This update is sent only
496*7c478bd9Sstevel@tonic-gate  * on interfaces other than the one on which we received notice
497*7c478bd9Sstevel@tonic-gate  * of the change.  If we are within MIN_WAIT_TIME of a full update,
498*7c478bd9Sstevel@tonic-gate  * don't bother sending; if we just sent a dynamic update
499*7c478bd9Sstevel@tonic-gate  * and set a timer (nextmcast), delay until that time.
500*7c478bd9Sstevel@tonic-gate  * If we just sent a full update, delay the dynamic update.
501*7c478bd9Sstevel@tonic-gate  * Set a timer for a randomized value to suppress additional
502*7c478bd9Sstevel@tonic-gate  * dynamic updates until it expires; if we delayed sending
503*7c478bd9Sstevel@tonic-gate  * the current changes, set needupdate.
504*7c478bd9Sstevel@tonic-gate  */
505*7c478bd9Sstevel@tonic-gate void
dynamic_update(struct interface * ifp)506*7c478bd9Sstevel@tonic-gate dynamic_update(struct interface *ifp)
507*7c478bd9Sstevel@tonic-gate {
508*7c478bd9Sstevel@tonic-gate 	int delay;
509*7c478bd9Sstevel@tonic-gate 
510*7c478bd9Sstevel@tonic-gate 	if (now.tv_sec - lastfullupdate.tv_sec >=
511*7c478bd9Sstevel@tonic-gate 	    supplyinterval - MIN_WAIT_TIME)
512*7c478bd9Sstevel@tonic-gate 		return;
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	if (now.tv_sec - lastmcast.tv_sec >= MIN_WAIT_TIME &&
515*7c478bd9Sstevel@tonic-gate 	    /* BEGIN CSTYLED */
516*7c478bd9Sstevel@tonic-gate 	    timercmp(&nextmcast, &now, <)) {
517*7c478bd9Sstevel@tonic-gate 	    /* END CSTYLED */
518*7c478bd9Sstevel@tonic-gate 		TRACE_ACTION("send dynamic update",
519*7c478bd9Sstevel@tonic-gate 		    (struct rt_entry *)NULL);
520*7c478bd9Sstevel@tonic-gate 		supplyall(&allrouters, RTS_CHANGED, ifp, _B_TRUE);
521*7c478bd9Sstevel@tonic-gate 		lastmcast = now;
522*7c478bd9Sstevel@tonic-gate 		needupdate = _B_FALSE;
523*7c478bd9Sstevel@tonic-gate 		nextmcast.tv_sec = 0;
524*7c478bd9Sstevel@tonic-gate 	} else {
525*7c478bd9Sstevel@tonic-gate 		needupdate = _B_TRUE;
526*7c478bd9Sstevel@tonic-gate 		TRACE_ACTION("delay dynamic update",
527*7c478bd9Sstevel@tonic-gate 		    (struct rt_entry *)NULL);
528*7c478bd9Sstevel@tonic-gate 	}
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	if (nextmcast.tv_sec == 0) {
531*7c478bd9Sstevel@tonic-gate 		delay = GET_RANDOM(MIN_WAIT_TIME * 1000000,
532*7c478bd9Sstevel@tonic-gate 		    MAX_WAIT_TIME * 1000000);
533*7c478bd9Sstevel@tonic-gate 		if (tracing & ACTION_BIT) {
534*7c478bd9Sstevel@tonic-gate 			(void) fprintf(ftrace,
535*7c478bd9Sstevel@tonic-gate 			    "inhibit dynamic update for %d msec\n",
536*7c478bd9Sstevel@tonic-gate 			    delay / 1000);
537*7c478bd9Sstevel@tonic-gate 			(void) fflush(ftrace);
538*7c478bd9Sstevel@tonic-gate 		}
539*7c478bd9Sstevel@tonic-gate 		nextmcast.tv_sec = delay / 1000000;
540*7c478bd9Sstevel@tonic-gate 		nextmcast.tv_usec = delay % 1000000;
541*7c478bd9Sstevel@tonic-gate 		timevaladd(&nextmcast, &now);
542*7c478bd9Sstevel@tonic-gate 		/*
543*7c478bd9Sstevel@tonic-gate 		 * If the next possibly dynamic update
544*7c478bd9Sstevel@tonic-gate 		 * is within MIN_WAIT_TIME of the next full
545*7c478bd9Sstevel@tonic-gate 		 * update, force the delay past the full
546*7c478bd9Sstevel@tonic-gate 		 * update, or we might send a dynamic update
547*7c478bd9Sstevel@tonic-gate 		 * just before the full update.
548*7c478bd9Sstevel@tonic-gate 		 */
549*7c478bd9Sstevel@tonic-gate 		if (nextmcast.tv_sec >
550*7c478bd9Sstevel@tonic-gate 		    lastfullupdate.tv_sec + supplyinterval - MIN_WAIT_TIME) {
551*7c478bd9Sstevel@tonic-gate 			nextmcast.tv_sec =
552*7c478bd9Sstevel@tonic-gate 			    lastfullupdate.tv_sec + supplyinterval + 1;
553*7c478bd9Sstevel@tonic-gate 		}
554*7c478bd9Sstevel@tonic-gate 	}
555*7c478bd9Sstevel@tonic-gate }
556