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 * 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 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 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 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