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