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