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 2004 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 #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include "defs.h" 30*7c478bd9Sstevel@tonic-gate #include "tables.h" 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate static boolean_t verify_opt_len(struct nd_opt_hdr *opt, int optlen, 35*7c478bd9Sstevel@tonic-gate struct phyint *pi, struct sockaddr_in6 *from); 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate static void incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, 38*7c478bd9Sstevel@tonic-gate int len, struct sockaddr_in6 *from); 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate void incoming_ra(struct phyint *pi, struct nd_router_advert *ra, 41*7c478bd9Sstevel@tonic-gate int len, struct sockaddr_in6 *from, boolean_t loopback); 42*7c478bd9Sstevel@tonic-gate static void incoming_prefix_opt(struct phyint *pi, uchar_t *opt, 43*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback); 44*7c478bd9Sstevel@tonic-gate static void incoming_prefix_onlink(struct phyint *pi, uchar_t *opt, 45*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback); 46*7c478bd9Sstevel@tonic-gate void incoming_prefix_onlink_process(struct prefix *pr, 47*7c478bd9Sstevel@tonic-gate uchar_t *opt); 48*7c478bd9Sstevel@tonic-gate static boolean_t incoming_prefix_addrconf(struct phyint *pi, 49*7c478bd9Sstevel@tonic-gate uchar_t *opt, struct sockaddr_in6 *from, 50*7c478bd9Sstevel@tonic-gate boolean_t loopback); 51*7c478bd9Sstevel@tonic-gate boolean_t incoming_prefix_addrconf_process(struct phyint *pi, 52*7c478bd9Sstevel@tonic-gate struct prefix *pr, uchar_t *opt, 53*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback, 54*7c478bd9Sstevel@tonic-gate boolean_t new_prefix); 55*7c478bd9Sstevel@tonic-gate static void incoming_mtu_opt(struct phyint *pi, uchar_t *opt, 56*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from); 57*7c478bd9Sstevel@tonic-gate static void incoming_lla_opt(struct phyint *pi, uchar_t *opt, 58*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, int isrouter); 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate static void verify_ra_consistency(struct phyint *pi, 61*7c478bd9Sstevel@tonic-gate struct nd_router_advert *ra, 62*7c478bd9Sstevel@tonic-gate int len, struct sockaddr_in6 *from); 63*7c478bd9Sstevel@tonic-gate static void verify_prefix_opt(struct phyint *pi, uchar_t *opt, 64*7c478bd9Sstevel@tonic-gate char *frombuf); 65*7c478bd9Sstevel@tonic-gate static void verify_mtu_opt(struct phyint *pi, uchar_t *opt, 66*7c478bd9Sstevel@tonic-gate char *frombuf); 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate static uint_t ra_flags; /* Global to detect when to trigger DHCP */ 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate /* 71*7c478bd9Sstevel@tonic-gate * Return a pointer to the specified option buffer. 72*7c478bd9Sstevel@tonic-gate * If not found return NULL. 73*7c478bd9Sstevel@tonic-gate */ 74*7c478bd9Sstevel@tonic-gate static void * 75*7c478bd9Sstevel@tonic-gate find_ancillary(struct msghdr *msg, int cmsg_type) 76*7c478bd9Sstevel@tonic-gate { 77*7c478bd9Sstevel@tonic-gate struct cmsghdr *cmsg; 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 80*7c478bd9Sstevel@tonic-gate cmsg = CMSG_NXTHDR(msg, cmsg)) { 81*7c478bd9Sstevel@tonic-gate if (cmsg->cmsg_level == IPPROTO_IPV6 && 82*7c478bd9Sstevel@tonic-gate cmsg->cmsg_type == cmsg_type) { 83*7c478bd9Sstevel@tonic-gate return (CMSG_DATA(cmsg)); 84*7c478bd9Sstevel@tonic-gate } 85*7c478bd9Sstevel@tonic-gate } 86*7c478bd9Sstevel@tonic-gate return (NULL); 87*7c478bd9Sstevel@tonic-gate } 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate void 90*7c478bd9Sstevel@tonic-gate in_data(struct phyint *pi) 91*7c478bd9Sstevel@tonic-gate { 92*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 from; 93*7c478bd9Sstevel@tonic-gate struct icmp6_hdr *icmp; 94*7c478bd9Sstevel@tonic-gate struct nd_router_solicit *rs; 95*7c478bd9Sstevel@tonic-gate struct nd_router_advert *ra; 96*7c478bd9Sstevel@tonic-gate static uint64_t in_packet[(IP_MAXPACKET + 1)/8]; 97*7c478bd9Sstevel@tonic-gate static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8]; 98*7c478bd9Sstevel@tonic-gate int len; 99*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 100*7c478bd9Sstevel@tonic-gate const char *msgbuf; 101*7c478bd9Sstevel@tonic-gate struct msghdr msg; 102*7c478bd9Sstevel@tonic-gate struct iovec iov; 103*7c478bd9Sstevel@tonic-gate uchar_t *opt; 104*7c478bd9Sstevel@tonic-gate uint_t hoplimit; 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate iov.iov_base = (char *)in_packet; 107*7c478bd9Sstevel@tonic-gate iov.iov_len = sizeof (in_packet); 108*7c478bd9Sstevel@tonic-gate msg.msg_iov = &iov; 109*7c478bd9Sstevel@tonic-gate msg.msg_iovlen = 1; 110*7c478bd9Sstevel@tonic-gate msg.msg_name = (struct sockaddr *)&from; 111*7c478bd9Sstevel@tonic-gate msg.msg_namelen = sizeof (from); 112*7c478bd9Sstevel@tonic-gate msg.msg_control = ancillary_data; 113*7c478bd9Sstevel@tonic-gate msg.msg_controllen = sizeof (ancillary_data); 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate if ((len = recvmsg(pi->pi_sock, &msg, 0)) < 0) { 116*7c478bd9Sstevel@tonic-gate logperror_pi(pi, "in_data: recvfrom"); 117*7c478bd9Sstevel@tonic-gate return; 118*7c478bd9Sstevel@tonic-gate } 119*7c478bd9Sstevel@tonic-gate if (len == 0) 120*7c478bd9Sstevel@tonic-gate return; 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate if (inet_ntop(AF_INET6, (void *)&from.sin6_addr, 123*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)) == NULL) 124*7c478bd9Sstevel@tonic-gate msgbuf = "Unspecified Router"; 125*7c478bd9Sstevel@tonic-gate else 126*7c478bd9Sstevel@tonic-gate msgbuf = abuf; 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate /* Ignore packets > 64k or control buffers that don't fit */ 129*7c478bd9Sstevel@tonic-gate if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { 130*7c478bd9Sstevel@tonic-gate if (debug & D_PKTBAD) { 131*7c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Truncated message: msg_flags 0x%x " 132*7c478bd9Sstevel@tonic-gate "from %s\n", msg.msg_flags, msgbuf); 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate return; 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate icmp = (struct icmp6_hdr *)in_packet; 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate if (len < ICMP6_MINLEN) { 140*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Too short ICMP packet: %d bytes " 141*7c478bd9Sstevel@tonic-gate "from %s on %s\n", 142*7c478bd9Sstevel@tonic-gate len, msgbuf, pi->pi_name); 143*7c478bd9Sstevel@tonic-gate return; 144*7c478bd9Sstevel@tonic-gate } 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate opt = find_ancillary(&msg, IPV6_HOPLIMIT); 147*7c478bd9Sstevel@tonic-gate if (opt == NULL) { 148*7c478bd9Sstevel@tonic-gate /* Unknown hoplimit - must drop */ 149*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Unknown hop limit from %s on %s\n", 150*7c478bd9Sstevel@tonic-gate msgbuf, pi->pi_name); 151*7c478bd9Sstevel@tonic-gate return; 152*7c478bd9Sstevel@tonic-gate } 153*7c478bd9Sstevel@tonic-gate hoplimit = *(uint_t *)opt; 154*7c478bd9Sstevel@tonic-gate opt = find_ancillary(&msg, IPV6_RTHDR); 155*7c478bd9Sstevel@tonic-gate if (opt != NULL) { 156*7c478bd9Sstevel@tonic-gate /* Can't allow routing headers in ND messages */ 157*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "ND message with routing header " 158*7c478bd9Sstevel@tonic-gate "from %s on %s\n", 159*7c478bd9Sstevel@tonic-gate msgbuf, pi->pi_name); 160*7c478bd9Sstevel@tonic-gate return; 161*7c478bd9Sstevel@tonic-gate } 162*7c478bd9Sstevel@tonic-gate switch (icmp->icmp6_type) { 163*7c478bd9Sstevel@tonic-gate case ND_ROUTER_SOLICIT: 164*7c478bd9Sstevel@tonic-gate if (!pi->pi_AdvSendAdvertisements) 165*7c478bd9Sstevel@tonic-gate return; 166*7c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 167*7c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 168*7c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Ignore received RS packet " 169*7c478bd9Sstevel@tonic-gate "on %s (no route exchange on interface)\n", 170*7c478bd9Sstevel@tonic-gate pi->pi_name); 171*7c478bd9Sstevel@tonic-gate } 172*7c478bd9Sstevel@tonic-gate return; 173*7c478bd9Sstevel@tonic-gate } 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate /* 176*7c478bd9Sstevel@tonic-gate * Assumes that the kernel has verified the AH (if present) 177*7c478bd9Sstevel@tonic-gate * and the ICMP checksum. 178*7c478bd9Sstevel@tonic-gate */ 179*7c478bd9Sstevel@tonic-gate if (hoplimit != IPV6_MAX_HOPS) { 180*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RS hop limit: %d from %s on %s\n", 181*7c478bd9Sstevel@tonic-gate hoplimit, msgbuf, pi->pi_name); 182*7c478bd9Sstevel@tonic-gate return; 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate if (icmp->icmp6_code != 0) { 186*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RS code: %d from %s on %s\n", 187*7c478bd9Sstevel@tonic-gate icmp->icmp6_code, msgbuf, pi->pi_name); 188*7c478bd9Sstevel@tonic-gate return; 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate if (len < sizeof (struct nd_router_solicit)) { 192*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RS too short: %d bytes " 193*7c478bd9Sstevel@tonic-gate "from %s on %s\n", 194*7c478bd9Sstevel@tonic-gate len, msgbuf, pi->pi_name); 195*7c478bd9Sstevel@tonic-gate return; 196*7c478bd9Sstevel@tonic-gate } 197*7c478bd9Sstevel@tonic-gate rs = (struct nd_router_solicit *)icmp; 198*7c478bd9Sstevel@tonic-gate if (len > sizeof (struct nd_router_solicit)) { 199*7c478bd9Sstevel@tonic-gate if (!verify_opt_len((struct nd_opt_hdr *)&rs[1], 200*7c478bd9Sstevel@tonic-gate len - sizeof (struct nd_router_solicit), pi, &from)) 201*7c478bd9Sstevel@tonic-gate return; 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 204*7c478bd9Sstevel@tonic-gate print_route_sol("Received valid solicit from ", pi, 205*7c478bd9Sstevel@tonic-gate rs, len, &from); 206*7c478bd9Sstevel@tonic-gate } 207*7c478bd9Sstevel@tonic-gate incoming_rs(pi, rs, len, &from); 208*7c478bd9Sstevel@tonic-gate break; 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate case ND_ROUTER_ADVERT: 211*7c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr)) { 212*7c478bd9Sstevel@tonic-gate /* 213*7c478bd9Sstevel@tonic-gate * Router advt. must have address! 214*7c478bd9Sstevel@tonic-gate * Logging the news and returning. 215*7c478bd9Sstevel@tonic-gate */ 216*7c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, 217*7c478bd9Sstevel@tonic-gate "Router's address unspecified in advertisement\n"); 218*7c478bd9Sstevel@tonic-gate return; 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate if (pi->pi_flags & IFF_NORTEXCH) { 221*7c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 222*7c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "Ignore received RA packet " 223*7c478bd9Sstevel@tonic-gate "on %s (no route exchange on interface)\n", 224*7c478bd9Sstevel@tonic-gate pi->pi_name); 225*7c478bd9Sstevel@tonic-gate } 226*7c478bd9Sstevel@tonic-gate return; 227*7c478bd9Sstevel@tonic-gate } 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate /* 230*7c478bd9Sstevel@tonic-gate * Assumes that the kernel has verified the AH (if present) 231*7c478bd9Sstevel@tonic-gate * and the ICMP checksum. 232*7c478bd9Sstevel@tonic-gate */ 233*7c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) { 234*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s - not link local on %s\n", 235*7c478bd9Sstevel@tonic-gate msgbuf, pi->pi_name); 236*7c478bd9Sstevel@tonic-gate return; 237*7c478bd9Sstevel@tonic-gate } 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate if (hoplimit != IPV6_MAX_HOPS) { 240*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA hop limit: %d from %s on %s\n", 241*7c478bd9Sstevel@tonic-gate hoplimit, msgbuf, pi->pi_name); 242*7c478bd9Sstevel@tonic-gate return; 243*7c478bd9Sstevel@tonic-gate } 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate if (icmp->icmp6_code != 0) { 246*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA code: %d from %s on %s\n", 247*7c478bd9Sstevel@tonic-gate icmp->icmp6_code, msgbuf, pi->pi_name); 248*7c478bd9Sstevel@tonic-gate return; 249*7c478bd9Sstevel@tonic-gate } 250*7c478bd9Sstevel@tonic-gate 251*7c478bd9Sstevel@tonic-gate if (len < sizeof (struct nd_router_advert)) { 252*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA too short: %d bytes " 253*7c478bd9Sstevel@tonic-gate "from %s on %s\n", 254*7c478bd9Sstevel@tonic-gate len, msgbuf, pi->pi_name); 255*7c478bd9Sstevel@tonic-gate return; 256*7c478bd9Sstevel@tonic-gate } 257*7c478bd9Sstevel@tonic-gate ra = (struct nd_router_advert *)icmp; 258*7c478bd9Sstevel@tonic-gate if (len > sizeof (struct nd_router_advert)) { 259*7c478bd9Sstevel@tonic-gate if (!verify_opt_len((struct nd_opt_hdr *)&ra[1], 260*7c478bd9Sstevel@tonic-gate len - sizeof (struct nd_router_advert), pi, &from)) 261*7c478bd9Sstevel@tonic-gate return; 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate if (debug & D_PKTIN) { 264*7c478bd9Sstevel@tonic-gate print_route_adv("Received valid advert from ", pi, 265*7c478bd9Sstevel@tonic-gate ra, len, &from); 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate if (pi->pi_AdvSendAdvertisements) 268*7c478bd9Sstevel@tonic-gate verify_ra_consistency(pi, ra, len, &from); 269*7c478bd9Sstevel@tonic-gate else 270*7c478bd9Sstevel@tonic-gate incoming_ra(pi, ra, len, &from, _B_FALSE); 271*7c478bd9Sstevel@tonic-gate break; 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate } 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate /* 276*7c478bd9Sstevel@tonic-gate * Process a received router solicitation. 277*7c478bd9Sstevel@tonic-gate * Check for source link-layer address option and check if it 278*7c478bd9Sstevel@tonic-gate * is time to advertise. 279*7c478bd9Sstevel@tonic-gate */ 280*7c478bd9Sstevel@tonic-gate static void 281*7c478bd9Sstevel@tonic-gate incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, int len, 282*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from) 283*7c478bd9Sstevel@tonic-gate { 284*7c478bd9Sstevel@tonic-gate struct nd_opt_hdr *opt; 285*7c478bd9Sstevel@tonic-gate int optlen; 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate /* Process any options */ 288*7c478bd9Sstevel@tonic-gate len -= sizeof (struct nd_router_solicit); 289*7c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)&rs[1]; 290*7c478bd9Sstevel@tonic-gate while (len >= sizeof (struct nd_opt_hdr)) { 291*7c478bd9Sstevel@tonic-gate optlen = opt->nd_opt_len * 8; 292*7c478bd9Sstevel@tonic-gate switch (opt->nd_opt_type) { 293*7c478bd9Sstevel@tonic-gate case ND_OPT_SOURCE_LINKADDR: 294*7c478bd9Sstevel@tonic-gate incoming_lla_opt(pi, (uchar_t *)opt, 295*7c478bd9Sstevel@tonic-gate from, NDF_ISROUTER_OFF); 296*7c478bd9Sstevel@tonic-gate break; 297*7c478bd9Sstevel@tonic-gate default: 298*7c478bd9Sstevel@tonic-gate break; 299*7c478bd9Sstevel@tonic-gate } 300*7c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + optlen); 301*7c478bd9Sstevel@tonic-gate len -= optlen; 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate /* Simple algorithm: treat unicast and multicast RSs the same */ 304*7c478bd9Sstevel@tonic-gate check_to_advertise(pi, RECEIVED_SOLICIT); 305*7c478bd9Sstevel@tonic-gate } 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate /* 308*7c478bd9Sstevel@tonic-gate * Process a received router advertisement. 309*7c478bd9Sstevel@tonic-gate * Called both when packets arrive as well as when we send RAs. 310*7c478bd9Sstevel@tonic-gate * In the latter case 'loopback' is set. 311*7c478bd9Sstevel@tonic-gate */ 312*7c478bd9Sstevel@tonic-gate void 313*7c478bd9Sstevel@tonic-gate incoming_ra(struct phyint *pi, struct nd_router_advert *ra, int len, 314*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback) 315*7c478bd9Sstevel@tonic-gate { 316*7c478bd9Sstevel@tonic-gate struct nd_opt_hdr *opt; 317*7c478bd9Sstevel@tonic-gate int optlen; 318*7c478bd9Sstevel@tonic-gate struct lifreq lifr; 319*7c478bd9Sstevel@tonic-gate boolean_t set_needed = _B_FALSE; 320*7c478bd9Sstevel@tonic-gate struct router *dr; 321*7c478bd9Sstevel@tonic-gate uint16_t router_lifetime; 322*7c478bd9Sstevel@tonic-gate uint_t reachable, retrans; 323*7c478bd9Sstevel@tonic-gate boolean_t reachable_time_changed = _B_FALSE; 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate if (no_loopback && loopback) 326*7c478bd9Sstevel@tonic-gate return; 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate /* 329*7c478bd9Sstevel@tonic-gate * If the interface is FAILED or INACTIVE or OFFLINE, don't 330*7c478bd9Sstevel@tonic-gate * create any addresses on them. in.mpathd assumes that no new 331*7c478bd9Sstevel@tonic-gate * addresses will appear on these. This implies that we 332*7c478bd9Sstevel@tonic-gate * won't create any new prefixes advertised by the router 333*7c478bd9Sstevel@tonic-gate * on FAILED/INACTIVE/OFFLINE interfaces. When the state changes, 334*7c478bd9Sstevel@tonic-gate * the next RA will create the prefix on this interface. 335*7c478bd9Sstevel@tonic-gate */ 336*7c478bd9Sstevel@tonic-gate if (pi->pi_flags & (IFF_FAILED|IFF_INACTIVE|IFF_OFFLINE)) 337*7c478bd9Sstevel@tonic-gate return; 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 340*7c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 341*7c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCGLIFLNKINFO, (char *)&lifr) < 0) { 342*7c478bd9Sstevel@tonic-gate if (errno == ENXIO) 343*7c478bd9Sstevel@tonic-gate return; 344*7c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_ra: SIOCGLIFLNKINFO"); 345*7c478bd9Sstevel@tonic-gate return; 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate if (ra->nd_ra_curhoplimit != pi->pi_CurHopLimit) { 348*7c478bd9Sstevel@tonic-gate pi->pi_CurHopLimit = ra->nd_ra_curhoplimit; 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit; 351*7c478bd9Sstevel@tonic-gate set_needed = _B_TRUE; 352*7c478bd9Sstevel@tonic-gate } 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate reachable = ntohl(ra->nd_ra_reachable); 355*7c478bd9Sstevel@tonic-gate if (reachable != 0 && 356*7c478bd9Sstevel@tonic-gate reachable != pi->pi_BaseReachableTime) { 357*7c478bd9Sstevel@tonic-gate pi->pi_BaseReachableTime = reachable; 358*7c478bd9Sstevel@tonic-gate reachable_time_changed = _B_TRUE; 359*7c478bd9Sstevel@tonic-gate } 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate if (pi->pi_reach_time_since_random < MIN_REACH_RANDOM_INTERVAL || 362*7c478bd9Sstevel@tonic-gate reachable_time_changed) { 363*7c478bd9Sstevel@tonic-gate phyint_reach_random(pi, _B_FALSE); 364*7c478bd9Sstevel@tonic-gate set_needed = _B_TRUE; 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime; 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate retrans = ntohl(ra->nd_ra_retransmit); 369*7c478bd9Sstevel@tonic-gate if (retrans != 0 && 370*7c478bd9Sstevel@tonic-gate pi->pi_RetransTimer != retrans) { 371*7c478bd9Sstevel@tonic-gate pi->pi_RetransTimer = retrans; 372*7c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer; 373*7c478bd9Sstevel@tonic-gate set_needed = _B_TRUE; 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate if (set_needed) { 377*7c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 378*7c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_ra: SIOCSLIFLNKINFO"); 379*7c478bd9Sstevel@tonic-gate return; 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate } 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) && 384*7c478bd9Sstevel@tonic-gate !(ra_flags & ND_RA_FLAG_MANAGED)) { 385*7c478bd9Sstevel@tonic-gate ra_flags |= ND_RA_FLAG_MANAGED; 386*7c478bd9Sstevel@tonic-gate /* TODO trigger dhcpv6 */ 387*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "incoming_ra: trigger dhcp MANAGED\n"); 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) && 390*7c478bd9Sstevel@tonic-gate !(ra_flags & ND_RA_FLAG_OTHER)) { 391*7c478bd9Sstevel@tonic-gate ra_flags |= ND_RA_FLAG_OTHER; 392*7c478bd9Sstevel@tonic-gate if (!(ra_flags & ND_RA_FLAG_MANAGED)) { 393*7c478bd9Sstevel@tonic-gate /* TODO trigger dhcpv6 for non-address info */ 394*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "incoming_ra: trigger dhcp OTHER\n"); 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate } 397*7c478bd9Sstevel@tonic-gate /* Skip default router code if sent from ourselves */ 398*7c478bd9Sstevel@tonic-gate if (!loopback) { 399*7c478bd9Sstevel@tonic-gate /* Find and update or add default router in list */ 400*7c478bd9Sstevel@tonic-gate dr = router_lookup(pi, from->sin6_addr); 401*7c478bd9Sstevel@tonic-gate router_lifetime = ntohs(ra->nd_ra_router_lifetime); 402*7c478bd9Sstevel@tonic-gate if (dr == NULL) { 403*7c478bd9Sstevel@tonic-gate if (router_lifetime != 0) { 404*7c478bd9Sstevel@tonic-gate dr = router_create(pi, from->sin6_addr, 405*7c478bd9Sstevel@tonic-gate MILLISEC * router_lifetime); 406*7c478bd9Sstevel@tonic-gate timer_schedule(dr->dr_lifetime); 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate } else { 409*7c478bd9Sstevel@tonic-gate dr->dr_lifetime = MILLISEC * router_lifetime; 410*7c478bd9Sstevel@tonic-gate if (dr->dr_lifetime != 0) 411*7c478bd9Sstevel@tonic-gate timer_schedule(dr->dr_lifetime); 412*7c478bd9Sstevel@tonic-gate if ((dr->dr_lifetime != 0 && !dr->dr_inkernel) || 413*7c478bd9Sstevel@tonic-gate (dr->dr_lifetime == 0 && dr->dr_inkernel)) 414*7c478bd9Sstevel@tonic-gate router_update_k(dr); 415*7c478bd9Sstevel@tonic-gate } 416*7c478bd9Sstevel@tonic-gate } 417*7c478bd9Sstevel@tonic-gate /* Process any options */ 418*7c478bd9Sstevel@tonic-gate len -= sizeof (struct nd_router_advert); 419*7c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)&ra[1]; 420*7c478bd9Sstevel@tonic-gate while (len >= sizeof (struct nd_opt_hdr)) { 421*7c478bd9Sstevel@tonic-gate optlen = opt->nd_opt_len * 8; 422*7c478bd9Sstevel@tonic-gate switch (opt->nd_opt_type) { 423*7c478bd9Sstevel@tonic-gate case ND_OPT_PREFIX_INFORMATION: 424*7c478bd9Sstevel@tonic-gate incoming_prefix_opt(pi, (uchar_t *)opt, from, 425*7c478bd9Sstevel@tonic-gate loopback); 426*7c478bd9Sstevel@tonic-gate break; 427*7c478bd9Sstevel@tonic-gate case ND_OPT_MTU: 428*7c478bd9Sstevel@tonic-gate incoming_mtu_opt(pi, (uchar_t *)opt, from); 429*7c478bd9Sstevel@tonic-gate break; 430*7c478bd9Sstevel@tonic-gate case ND_OPT_SOURCE_LINKADDR: 431*7c478bd9Sstevel@tonic-gate /* skip lla option if sent from ourselves! */ 432*7c478bd9Sstevel@tonic-gate if (!loopback) { 433*7c478bd9Sstevel@tonic-gate incoming_lla_opt(pi, (uchar_t *)opt, 434*7c478bd9Sstevel@tonic-gate from, NDF_ISROUTER_ON); 435*7c478bd9Sstevel@tonic-gate } 436*7c478bd9Sstevel@tonic-gate break; 437*7c478bd9Sstevel@tonic-gate default: 438*7c478bd9Sstevel@tonic-gate break; 439*7c478bd9Sstevel@tonic-gate } 440*7c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + optlen); 441*7c478bd9Sstevel@tonic-gate len -= optlen; 442*7c478bd9Sstevel@tonic-gate } 443*7c478bd9Sstevel@tonic-gate /* Stop sending solicitations */ 444*7c478bd9Sstevel@tonic-gate check_to_solicit(pi, SOLICIT_DONE); 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate /* 448*7c478bd9Sstevel@tonic-gate * Process a received prefix option. 449*7c478bd9Sstevel@tonic-gate * Unless addrconf is turned off we process both the addrconf and the 450*7c478bd9Sstevel@tonic-gate * onlink aspects of the prefix option. 451*7c478bd9Sstevel@tonic-gate * 452*7c478bd9Sstevel@tonic-gate * Note that when a flag (onlink or auto) is turned off we do nothing - 453*7c478bd9Sstevel@tonic-gate * the prefix will time out. 454*7c478bd9Sstevel@tonic-gate */ 455*7c478bd9Sstevel@tonic-gate static void 456*7c478bd9Sstevel@tonic-gate incoming_prefix_opt(struct phyint *pi, uchar_t *opt, 457*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback) 458*7c478bd9Sstevel@tonic-gate { 459*7c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 460*7c478bd9Sstevel@tonic-gate boolean_t good_prefix = _B_TRUE; 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate if (8 * po->nd_opt_pi_len != sizeof (*po)) { 463*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 466*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 467*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "prefix option from %s on %s wrong size " 468*7c478bd9Sstevel@tonic-gate "(%d bytes)\n", 469*7c478bd9Sstevel@tonic-gate abuf, pi->pi_name, 470*7c478bd9Sstevel@tonic-gate 8 * (int)po->nd_opt_pi_len); 471*7c478bd9Sstevel@tonic-gate return; 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) { 474*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 477*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 478*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s contains link-local prefix " 479*7c478bd9Sstevel@tonic-gate "- ignored\n", 480*7c478bd9Sstevel@tonic-gate abuf, pi->pi_name); 481*7c478bd9Sstevel@tonic-gate return; 482*7c478bd9Sstevel@tonic-gate } 483*7c478bd9Sstevel@tonic-gate if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && 484*7c478bd9Sstevel@tonic-gate pi->pi_StatelessAddrConf) { 485*7c478bd9Sstevel@tonic-gate good_prefix = incoming_prefix_addrconf(pi, opt, from, loopback); 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && 488*7c478bd9Sstevel@tonic-gate good_prefix) { 489*7c478bd9Sstevel@tonic-gate incoming_prefix_onlink(pi, opt, from, loopback); 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate } 492*7c478bd9Sstevel@tonic-gate 493*7c478bd9Sstevel@tonic-gate /* 494*7c478bd9Sstevel@tonic-gate * Process prefix options with the onlink flag set. 495*7c478bd9Sstevel@tonic-gate * 496*7c478bd9Sstevel@tonic-gate * If there are no routers ndpd will add an onlink 497*7c478bd9Sstevel@tonic-gate * default route which will allow communication 498*7c478bd9Sstevel@tonic-gate * between neighbors. 499*7c478bd9Sstevel@tonic-gate * 500*7c478bd9Sstevel@tonic-gate * This function needs to loop to find the same prefix multiple times 501*7c478bd9Sstevel@tonic-gate * as if a failover happened earlier, the addresses belonging to 502*7c478bd9Sstevel@tonic-gate * a different interface may be found here on this interface. 503*7c478bd9Sstevel@tonic-gate */ 504*7c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 505*7c478bd9Sstevel@tonic-gate static void 506*7c478bd9Sstevel@tonic-gate incoming_prefix_onlink(struct phyint *pi, uchar_t *opt, 507*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback) 508*7c478bd9Sstevel@tonic-gate { 509*7c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 510*7c478bd9Sstevel@tonic-gate int plen; 511*7c478bd9Sstevel@tonic-gate struct prefix *pr; 512*7c478bd9Sstevel@tonic-gate uint32_t validtime; /* Without 2 hour rule */ 513*7c478bd9Sstevel@tonic-gate boolean_t found_one = _B_FALSE; 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate plen = po->nd_opt_pi_prefix_len; 516*7c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 517*7c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len == plen && 518*7c478bd9Sstevel@tonic-gate prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) { 519*7c478bd9Sstevel@tonic-gate /* Exclude static prefixes */ 520*7c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_STATIC) 521*7c478bd9Sstevel@tonic-gate continue; 522*7c478bd9Sstevel@tonic-gate found_one = _B_TRUE; 523*7c478bd9Sstevel@tonic-gate incoming_prefix_onlink_process(pr, opt); 524*7c478bd9Sstevel@tonic-gate } 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 528*7c478bd9Sstevel@tonic-gate /* 529*7c478bd9Sstevel@tonic-gate * If we have found a matching prefix already or validtime 530*7c478bd9Sstevel@tonic-gate * is zero, we have nothing to do. 531*7c478bd9Sstevel@tonic-gate */ 532*7c478bd9Sstevel@tonic-gate if (validtime == 0 || found_one) 533*7c478bd9Sstevel@tonic-gate return; 534*7c478bd9Sstevel@tonic-gate pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0); 535*7c478bd9Sstevel@tonic-gate if (pr == NULL) 536*7c478bd9Sstevel@tonic-gate return; 537*7c478bd9Sstevel@tonic-gate incoming_prefix_onlink_process(pr, opt); 538*7c478bd9Sstevel@tonic-gate } 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate void 541*7c478bd9Sstevel@tonic-gate incoming_prefix_onlink_process(struct prefix *pr, uchar_t *opt) 542*7c478bd9Sstevel@tonic-gate { 543*7c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 544*7c478bd9Sstevel@tonic-gate uint32_t validtime; /* Without 2 hour rule */ 545*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 548*7c478bd9Sstevel@tonic-gate if (validtime != 0) 549*7c478bd9Sstevel@tonic-gate pr->pr_state |= PR_ONLINK; 550*7c478bd9Sstevel@tonic-gate else 551*7c478bd9Sstevel@tonic-gate pr->pr_state &= ~PR_ONLINK; 552*7c478bd9Sstevel@tonic-gate 553*7c478bd9Sstevel@tonic-gate /* 554*7c478bd9Sstevel@tonic-gate * Convert from seconds to milliseconds avoiding overflow. 555*7c478bd9Sstevel@tonic-gate * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1 556*7c478bd9Sstevel@tonic-gate * (4 billion seconds - about 130 years) we will in fact time 557*7c478bd9Sstevel@tonic-gate * out the prefix after 4 billion milliseconds - 46 days). 558*7c478bd9Sstevel@tonic-gate * Thus the longest lifetime (apart from infinity) is 46 days. 559*7c478bd9Sstevel@tonic-gate * Note that this ensures that PREFIX_INFINITY still means "forever". 560*7c478bd9Sstevel@tonic-gate */ 561*7c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) { 562*7c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = pr->pr_ValidLifetime; 563*7c478bd9Sstevel@tonic-gate } else { 564*7c478bd9Sstevel@tonic-gate if (validtime >= PREFIX_INFINITY / MILLISEC) 565*7c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = PREFIX_INFINITY - 1; 566*7c478bd9Sstevel@tonic-gate else 567*7c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime = validtime * MILLISEC; 568*7c478bd9Sstevel@tonic-gate } 569*7c478bd9Sstevel@tonic-gate pr->pr_OnLinkFlag = _B_TRUE; 570*7c478bd9Sstevel@tonic-gate if (debug & (D_PREFIX|D_TMP)) { 571*7c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "incoming_prefix_onlink_process(%s, %s/%u) " 572*7c478bd9Sstevel@tonic-gate "onlink %u state 0x%x, kstate 0x%x\n", 573*7c478bd9Sstevel@tonic-gate pr->pr_name, inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 574*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 575*7c478bd9Sstevel@tonic-gate pr->pr_OnLinkLifetime, pr->pr_state, pr->pr_kernel_state); 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state != pr->pr_state) { 579*7c478bd9Sstevel@tonic-gate prefix_update_k(pr); 580*7c478bd9Sstevel@tonic-gate } 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate if (pr->pr_OnLinkLifetime != 0) 583*7c478bd9Sstevel@tonic-gate timer_schedule(pr->pr_OnLinkLifetime); 584*7c478bd9Sstevel@tonic-gate } 585*7c478bd9Sstevel@tonic-gate 586*7c478bd9Sstevel@tonic-gate /* 587*7c478bd9Sstevel@tonic-gate * Process prefix options with the autonomous flag set. 588*7c478bd9Sstevel@tonic-gate * Returns false if this prefix results in a bad address (duplicate) 589*7c478bd9Sstevel@tonic-gate * This function needs to loop to find the same prefix multiple times 590*7c478bd9Sstevel@tonic-gate * as if a failover happened earlier, the addresses belonging to 591*7c478bd9Sstevel@tonic-gate * a different interface may be found here on this interface. 592*7c478bd9Sstevel@tonic-gate */ 593*7c478bd9Sstevel@tonic-gate /* ARGSUSED2 */ 594*7c478bd9Sstevel@tonic-gate static boolean_t 595*7c478bd9Sstevel@tonic-gate incoming_prefix_addrconf(struct phyint *pi, uchar_t *opt, 596*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, boolean_t loopback) 597*7c478bd9Sstevel@tonic-gate { 598*7c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 599*7c478bd9Sstevel@tonic-gate int plen; 600*7c478bd9Sstevel@tonic-gate struct prefix *pr; 601*7c478bd9Sstevel@tonic-gate uint32_t validtime, preftime; /* In seconds */ 602*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 603*7c478bd9Sstevel@tonic-gate char pbuf[INET6_ADDRSTRLEN]; 604*7c478bd9Sstevel@tonic-gate boolean_t found_pub = _B_FALSE; 605*7c478bd9Sstevel@tonic-gate boolean_t found_tmp = _B_FALSE; 606*7c478bd9Sstevel@tonic-gate boolean_t ret; 607*7c478bd9Sstevel@tonic-gate 608*7c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 609*7c478bd9Sstevel@tonic-gate preftime = ntohl(po->nd_opt_pi_preferred_time); 610*7c478bd9Sstevel@tonic-gate plen = po->nd_opt_pi_prefix_len; 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate /* Sanity checks */ 613*7c478bd9Sstevel@tonic-gate if (validtime < preftime) { 614*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 615*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 616*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 617*7c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 618*7c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 619*7c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "prefix option %s/%u from %s on %s: " 620*7c478bd9Sstevel@tonic-gate "valid %u < pref %u ignored\n", 621*7c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, 622*7c478bd9Sstevel@tonic-gate validtime, preftime); 623*7c478bd9Sstevel@tonic-gate return (_B_FALSE); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { 627*7c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len == plen && 628*7c478bd9Sstevel@tonic-gate prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) { 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate /* Exclude static prefixes */ 631*7c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_STATIC) 632*7c478bd9Sstevel@tonic-gate continue; 633*7c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) { 634*7c478bd9Sstevel@tonic-gate /* 635*7c478bd9Sstevel@tonic-gate * If this address is deprecated and its token 636*7c478bd9Sstevel@tonic-gate * doesn't match the current tmp token, we want 637*7c478bd9Sstevel@tonic-gate * to create a new address with the current 638*7c478bd9Sstevel@tonic-gate * token. So don't count this addr as a match. 639*7c478bd9Sstevel@tonic-gate */ 640*7c478bd9Sstevel@tonic-gate if (!((pr->pr_flags & IFF_DEPRECATED) && 641*7c478bd9Sstevel@tonic-gate !token_equal(pi->pi_tmp_token, 642*7c478bd9Sstevel@tonic-gate pr->pr_address, TMP_TOKEN_BITS))) 643*7c478bd9Sstevel@tonic-gate found_tmp = _B_TRUE; 644*7c478bd9Sstevel@tonic-gate } else { 645*7c478bd9Sstevel@tonic-gate found_pub = _B_TRUE; 646*7c478bd9Sstevel@tonic-gate } 647*7c478bd9Sstevel@tonic-gate (void) incoming_prefix_addrconf_process(pi, pr, opt, 648*7c478bd9Sstevel@tonic-gate from, loopback, _B_FALSE); 649*7c478bd9Sstevel@tonic-gate } 650*7c478bd9Sstevel@tonic-gate } 651*7c478bd9Sstevel@tonic-gate 652*7c478bd9Sstevel@tonic-gate /* 653*7c478bd9Sstevel@tonic-gate * If we have found a matching prefix (for public and, if temp addrs 654*7c478bd9Sstevel@tonic-gate * are enabled, for temporary) already or validtime is zero, we have 655*7c478bd9Sstevel@tonic-gate * nothing to do. 656*7c478bd9Sstevel@tonic-gate */ 657*7c478bd9Sstevel@tonic-gate if (validtime == 0 || 658*7c478bd9Sstevel@tonic-gate (found_pub && (!pi->pi_TmpAddrsEnabled || found_tmp))) 659*7c478bd9Sstevel@tonic-gate return (_B_TRUE); 660*7c478bd9Sstevel@tonic-gate 661*7c478bd9Sstevel@tonic-gate if (!found_pub) { 662*7c478bd9Sstevel@tonic-gate pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0); 663*7c478bd9Sstevel@tonic-gate if (pr == NULL) 664*7c478bd9Sstevel@tonic-gate return (_B_TRUE); 665*7c478bd9Sstevel@tonic-gate ret = incoming_prefix_addrconf_process(pi, pr, opt, from, 666*7c478bd9Sstevel@tonic-gate loopback, _B_TRUE); 667*7c478bd9Sstevel@tonic-gate } 668*7c478bd9Sstevel@tonic-gate /* 669*7c478bd9Sstevel@tonic-gate * if processing of the public address failed, 670*7c478bd9Sstevel@tonic-gate * don't bother with the temporary address. 671*7c478bd9Sstevel@tonic-gate */ 672*7c478bd9Sstevel@tonic-gate if (ret == _B_FALSE) 673*7c478bd9Sstevel@tonic-gate return (_B_FALSE); 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate if (pi->pi_TmpAddrsEnabled && !found_tmp) { 676*7c478bd9Sstevel@tonic-gate pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 677*7c478bd9Sstevel@tonic-gate IFF_TEMPORARY); 678*7c478bd9Sstevel@tonic-gate if (pr == NULL) 679*7c478bd9Sstevel@tonic-gate return (_B_TRUE); 680*7c478bd9Sstevel@tonic-gate ret = incoming_prefix_addrconf_process(pi, pr, opt, from, 681*7c478bd9Sstevel@tonic-gate loopback, _B_TRUE); 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate return (ret); 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate boolean_t 688*7c478bd9Sstevel@tonic-gate incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr, 689*7c478bd9Sstevel@tonic-gate uchar_t *opt, struct sockaddr_in6 *from, boolean_t loopback, 690*7c478bd9Sstevel@tonic-gate boolean_t new_prefix) 691*7c478bd9Sstevel@tonic-gate { 692*7c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 693*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 694*7c478bd9Sstevel@tonic-gate char pbuf[INET6_ADDRSTRLEN]; 695*7c478bd9Sstevel@tonic-gate uint32_t validtime, preftime; /* In seconds */ 696*7c478bd9Sstevel@tonic-gate uint32_t recorded_validtime; /* In seconds */ 697*7c478bd9Sstevel@tonic-gate int plen, dadfails = 0; 698*7c478bd9Sstevel@tonic-gate struct prefix *other_pr; 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 701*7c478bd9Sstevel@tonic-gate preftime = ntohl(po->nd_opt_pi_preferred_time); 702*7c478bd9Sstevel@tonic-gate plen = po->nd_opt_pi_prefix_len; 703*7c478bd9Sstevel@tonic-gate if (!new_prefix) { 704*7c478bd9Sstevel@tonic-gate /* 705*7c478bd9Sstevel@tonic-gate * Check 2 hour rule on valid lifetime. 706*7c478bd9Sstevel@tonic-gate * Follows: RFC 2462 707*7c478bd9Sstevel@tonic-gate * If we advertised this prefix ourselves we skip 708*7c478bd9Sstevel@tonic-gate * these checks. They are also skipped if we did not 709*7c478bd9Sstevel@tonic-gate * previously do addrconf on this prefix. 710*7c478bd9Sstevel@tonic-gate */ 711*7c478bd9Sstevel@tonic-gate recorded_validtime = pr->pr_ValidLifetime / MILLISEC; 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate if (loopback || !(pr->pr_state & PR_AUTO) || 714*7c478bd9Sstevel@tonic-gate validtime >= MIN_VALID_LIFETIME || 715*7c478bd9Sstevel@tonic-gate /* LINTED - statement has no consequent */ 716*7c478bd9Sstevel@tonic-gate validtime >= recorded_validtime) { 717*7c478bd9Sstevel@tonic-gate /* OK */ 718*7c478bd9Sstevel@tonic-gate } else if (recorded_validtime < MIN_VALID_LIFETIME && 719*7c478bd9Sstevel@tonic-gate validtime < recorded_validtime) { 720*7c478bd9Sstevel@tonic-gate /* Ignore the prefix */ 721*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 722*7c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 723*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 724*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 725*7c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 726*7c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 727*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 728*7c478bd9Sstevel@tonic-gate "too short valid lifetime %u stored %u " 729*7c478bd9Sstevel@tonic-gate "- ignored\n", 730*7c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, 731*7c478bd9Sstevel@tonic-gate validtime, recorded_validtime); 732*7c478bd9Sstevel@tonic-gate return (_B_TRUE); 733*7c478bd9Sstevel@tonic-gate } else { 734*7c478bd9Sstevel@tonic-gate /* 735*7c478bd9Sstevel@tonic-gate * If the router clock runs slower than the 736*7c478bd9Sstevel@tonic-gate * host by 1 second over 2 hours then this 737*7c478bd9Sstevel@tonic-gate * test will set the lifetime back to 2 hours 738*7c478bd9Sstevel@tonic-gate * once i.e. a lifetime decrementing in 739*7c478bd9Sstevel@tonic-gate * realtime might cause the prefix to live an 740*7c478bd9Sstevel@tonic-gate * extra 2 hours on the host. 741*7c478bd9Sstevel@tonic-gate */ 742*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 743*7c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 744*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 745*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 746*7c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 747*7c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 748*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 749*7c478bd9Sstevel@tonic-gate "valid time %u stored %u rounded up " 750*7c478bd9Sstevel@tonic-gate "to %u\n", 751*7c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, 752*7c478bd9Sstevel@tonic-gate validtime, recorded_validtime, 753*7c478bd9Sstevel@tonic-gate MIN_VALID_LIFETIME); 754*7c478bd9Sstevel@tonic-gate validtime = MIN_VALID_LIFETIME; 755*7c478bd9Sstevel@tonic-gate } 756*7c478bd9Sstevel@tonic-gate } 757*7c478bd9Sstevel@tonic-gate 758*7c478bd9Sstevel@tonic-gate /* 759*7c478bd9Sstevel@tonic-gate * For RFC3041 addresses, need to take token lifetime 760*7c478bd9Sstevel@tonic-gate * into account, too. 761*7c478bd9Sstevel@tonic-gate */ 762*7c478bd9Sstevel@tonic-gate if (pr->pr_flags & IFF_TEMPORARY) { 763*7c478bd9Sstevel@tonic-gate uint_t cur_tpreftime = 764*7c478bd9Sstevel@tonic-gate pi->pi_TmpPreferredLifetime - pi->pi_TmpDesyncFactor; 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate if (new_prefix) { 767*7c478bd9Sstevel@tonic-gate validtime = MIN(validtime, pi->pi_TmpValidLifetime); 768*7c478bd9Sstevel@tonic-gate preftime = MIN(preftime, cur_tpreftime); 769*7c478bd9Sstevel@tonic-gate } else { 770*7c478bd9Sstevel@tonic-gate uint_t cur_vexp, cur_pexp, curtime; 771*7c478bd9Sstevel@tonic-gate curtime = getcurrenttime() / MILLISEC; 772*7c478bd9Sstevel@tonic-gate 773*7c478bd9Sstevel@tonic-gate cur_vexp = pr->pr_CreateTime + pi->pi_TmpValidLifetime; 774*7c478bd9Sstevel@tonic-gate cur_pexp = pr->pr_CreateTime + cur_tpreftime; 775*7c478bd9Sstevel@tonic-gate if (curtime > cur_vexp) 776*7c478bd9Sstevel@tonic-gate validtime = 0; 777*7c478bd9Sstevel@tonic-gate else if ((curtime + validtime) > cur_vexp) 778*7c478bd9Sstevel@tonic-gate validtime = cur_vexp - curtime; 779*7c478bd9Sstevel@tonic-gate /* 780*7c478bd9Sstevel@tonic-gate * If this is an existing address which was deprecated 781*7c478bd9Sstevel@tonic-gate * because of a bad token, we don't want to update its 782*7c478bd9Sstevel@tonic-gate * preferred lifetime! 783*7c478bd9Sstevel@tonic-gate */ 784*7c478bd9Sstevel@tonic-gate if ((pr->pr_PreferredLifetime == 0) && 785*7c478bd9Sstevel@tonic-gate !token_equal(pr->pr_address, pi->pi_tmp_token, 786*7c478bd9Sstevel@tonic-gate TMP_TOKEN_BITS)) 787*7c478bd9Sstevel@tonic-gate preftime = 0; 788*7c478bd9Sstevel@tonic-gate else if (curtime > cur_pexp) 789*7c478bd9Sstevel@tonic-gate preftime = 0; 790*7c478bd9Sstevel@tonic-gate else if ((curtime + preftime) > cur_pexp) 791*7c478bd9Sstevel@tonic-gate preftime = cur_pexp - curtime; 792*7c478bd9Sstevel@tonic-gate } 793*7c478bd9Sstevel@tonic-gate if ((preftime != 0) && (preftime <= pi->pi_TmpRegenAdvance)) { 794*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 795*7c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 796*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 797*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 798*7c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 799*7c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 800*7c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "prefix opt %s/%u from %s on %s: " 801*7c478bd9Sstevel@tonic-gate "preferred lifetime(%d) <= TmpRegenAdvance(%d)\n", 802*7c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, preftime, 803*7c478bd9Sstevel@tonic-gate pi->pi_TmpRegenAdvance); 804*7c478bd9Sstevel@tonic-gate if (new_prefix) 805*7c478bd9Sstevel@tonic-gate prefix_delete(pr); 806*7c478bd9Sstevel@tonic-gate return (_B_TRUE); 807*7c478bd9Sstevel@tonic-gate } 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate if (debug & D_TMP) 810*7c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "calculated lifetimes(%s, 0x%llx): v %d, " 811*7c478bd9Sstevel@tonic-gate "p %d\n", pr->pr_name, pr->pr_flags, validtime, preftime); 812*7c478bd9Sstevel@tonic-gate 813*7c478bd9Sstevel@tonic-gate if (!(pr->pr_state & PR_AUTO)) { 814*7c478bd9Sstevel@tonic-gate int i, tokenlen; 815*7c478bd9Sstevel@tonic-gate in6_addr_t *token; 816*7c478bd9Sstevel@tonic-gate /* 817*7c478bd9Sstevel@tonic-gate * Form a new local address if the lengths match. 818*7c478bd9Sstevel@tonic-gate */ 819*7c478bd9Sstevel@tonic-gate if (pr->pr_flags && IFF_TEMPORARY) { 820*7c478bd9Sstevel@tonic-gate RETRY_TOKEN: 821*7c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_tmp_token)) { 822*7c478bd9Sstevel@tonic-gate if (!tmptoken_create(pi)) { 823*7c478bd9Sstevel@tonic-gate prefix_delete(pr); 824*7c478bd9Sstevel@tonic-gate return (_B_TRUE); 825*7c478bd9Sstevel@tonic-gate } 826*7c478bd9Sstevel@tonic-gate } 827*7c478bd9Sstevel@tonic-gate tokenlen = TMP_TOKEN_BITS; 828*7c478bd9Sstevel@tonic-gate token = &pi->pi_tmp_token; 829*7c478bd9Sstevel@tonic-gate } else { 830*7c478bd9Sstevel@tonic-gate tokenlen = pi->pi_token_length; 831*7c478bd9Sstevel@tonic-gate token = &pi->pi_token; 832*7c478bd9Sstevel@tonic-gate } 833*7c478bd9Sstevel@tonic-gate if (pr->pr_prefix_len + tokenlen != IPV6_ABITS) { 834*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 835*7c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 836*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 837*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 838*7c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, 839*7c478bd9Sstevel@tonic-gate pbuf, sizeof (pbuf)); 840*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " 841*7c478bd9Sstevel@tonic-gate "mismatched length %d token length %d\n", 842*7c478bd9Sstevel@tonic-gate pbuf, plen, abuf, pi->pi_name, 843*7c478bd9Sstevel@tonic-gate pr->pr_prefix_len, tokenlen); 844*7c478bd9Sstevel@tonic-gate return (_B_TRUE); 845*7c478bd9Sstevel@tonic-gate } 846*7c478bd9Sstevel@tonic-gate for (i = 0; i < 16; i++) { 847*7c478bd9Sstevel@tonic-gate /* 848*7c478bd9Sstevel@tonic-gate * prefix_create ensures that pr_prefix has all-zero 849*7c478bd9Sstevel@tonic-gate * bits after prefixlen. 850*7c478bd9Sstevel@tonic-gate */ 851*7c478bd9Sstevel@tonic-gate pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] | 852*7c478bd9Sstevel@tonic-gate token->s6_addr[i]; 853*7c478bd9Sstevel@tonic-gate } 854*7c478bd9Sstevel@tonic-gate /* 855*7c478bd9Sstevel@tonic-gate * Check if any other physical interface has the same 856*7c478bd9Sstevel@tonic-gate * address configured already 857*7c478bd9Sstevel@tonic-gate */ 858*7c478bd9Sstevel@tonic-gate if ((other_pr = prefix_lookup_addr_match(pr)) != NULL) { 859*7c478bd9Sstevel@tonic-gate /* 860*7c478bd9Sstevel@tonic-gate * Delete this prefix structure as kernel 861*7c478bd9Sstevel@tonic-gate * does not allow duplicated addresses 862*7c478bd9Sstevel@tonic-gate */ 863*7c478bd9Sstevel@tonic-gate 864*7c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "incoming_prefix_addrconf_process: " 865*7c478bd9Sstevel@tonic-gate "Duplicate prefix %s received on interface %s\n", 866*7c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, 867*7c478bd9Sstevel@tonic-gate (void *)&po->nd_opt_pi_prefix, abuf, 868*7c478bd9Sstevel@tonic-gate sizeof (abuf)), pi->pi_name); 869*7c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "incoming_prefix_addrconf_process: " 870*7c478bd9Sstevel@tonic-gate "Prefix already exists in interface %s\n", 871*7c478bd9Sstevel@tonic-gate other_pr->pr_physical->pi_name); 872*7c478bd9Sstevel@tonic-gate if (new_prefix) { 873*7c478bd9Sstevel@tonic-gate prefix_delete(pr); 874*7c478bd9Sstevel@tonic-gate return (_B_FALSE); 875*7c478bd9Sstevel@tonic-gate } 876*7c478bd9Sstevel@tonic-gate /* Ignore for addrconf purposes */ 877*7c478bd9Sstevel@tonic-gate validtime = preftime = 0; 878*7c478bd9Sstevel@tonic-gate } 879*7c478bd9Sstevel@tonic-gate if ((pr->pr_flags & IFF_TEMPORARY) && new_prefix) { 880*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6; 881*7c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 882*7c478bd9Sstevel@tonic-gate sin6.sin6_addr = pr->pr_address; 883*7c478bd9Sstevel@tonic-gate if (do_dad(pi->pi_name, &sin6) != 0) { 884*7c478bd9Sstevel@tonic-gate /* DAD failed, need a new token */ 885*7c478bd9Sstevel@tonic-gate dadfails++; 886*7c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, 887*7c478bd9Sstevel@tonic-gate "incoming_prefix_addrconf_process: " 888*7c478bd9Sstevel@tonic-gate "deprecating temporary token %s\n", 889*7c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, 890*7c478bd9Sstevel@tonic-gate (void *)&pi->pi_tmp_token, abuf, 891*7c478bd9Sstevel@tonic-gate sizeof (abuf))); 892*7c478bd9Sstevel@tonic-gate tmptoken_delete(pi); 893*7c478bd9Sstevel@tonic-gate if (dadfails == MAX_DAD_FAILURES) { 894*7c478bd9Sstevel@tonic-gate logmsg(LOG_ERR, "Too many DAD " 895*7c478bd9Sstevel@tonic-gate "failures; disabling temporary " 896*7c478bd9Sstevel@tonic-gate "addresses on %s\n", pi->pi_name); 897*7c478bd9Sstevel@tonic-gate pi->pi_TmpAddrsEnabled = 0; 898*7c478bd9Sstevel@tonic-gate prefix_delete(pr); 899*7c478bd9Sstevel@tonic-gate return (_B_TRUE); 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate goto RETRY_TOKEN; 902*7c478bd9Sstevel@tonic-gate } 903*7c478bd9Sstevel@tonic-gate pr->pr_CreateTime = getcurrenttime() / MILLISEC; 904*7c478bd9Sstevel@tonic-gate if (debug & D_TMP) 905*7c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, 906*7c478bd9Sstevel@tonic-gate "created tmp addr(%s v %d p %d)\n", 907*7c478bd9Sstevel@tonic-gate pr->pr_name, validtime, preftime); 908*7c478bd9Sstevel@tonic-gate } 909*7c478bd9Sstevel@tonic-gate } 910*7c478bd9Sstevel@tonic-gate 911*7c478bd9Sstevel@tonic-gate if (validtime != 0) 912*7c478bd9Sstevel@tonic-gate pr->pr_state |= PR_AUTO; 913*7c478bd9Sstevel@tonic-gate else 914*7c478bd9Sstevel@tonic-gate pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED); 915*7c478bd9Sstevel@tonic-gate if (preftime != 0 || !(pr->pr_state & PR_AUTO)) 916*7c478bd9Sstevel@tonic-gate pr->pr_state &= ~PR_DEPRECATED; 917*7c478bd9Sstevel@tonic-gate else 918*7c478bd9Sstevel@tonic-gate pr->pr_state |= PR_DEPRECATED; 919*7c478bd9Sstevel@tonic-gate 920*7c478bd9Sstevel@tonic-gate /* 921*7c478bd9Sstevel@tonic-gate * Convert from seconds to milliseconds avoiding overflow. 922*7c478bd9Sstevel@tonic-gate * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1 923*7c478bd9Sstevel@tonic-gate * (4 billion seconds - about 130 years) we will in fact time 924*7c478bd9Sstevel@tonic-gate * out the prefix after 4 billion milliseconds - 46 days). 925*7c478bd9Sstevel@tonic-gate * Thus the longest lifetime (apart from infinity) is 46 days. 926*7c478bd9Sstevel@tonic-gate * Note that this ensures that PREFIX_INFINITY still means "forever". 927*7c478bd9Sstevel@tonic-gate */ 928*7c478bd9Sstevel@tonic-gate if (validtime >= PREFIX_INFINITY / MILLISEC) 929*7c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime = PREFIX_INFINITY - 1; 930*7c478bd9Sstevel@tonic-gate else 931*7c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime = validtime * MILLISEC; 932*7c478bd9Sstevel@tonic-gate if (preftime >= PREFIX_INFINITY / MILLISEC) 933*7c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = PREFIX_INFINITY - 1; 934*7c478bd9Sstevel@tonic-gate else 935*7c478bd9Sstevel@tonic-gate pr->pr_PreferredLifetime = preftime * MILLISEC; 936*7c478bd9Sstevel@tonic-gate pr->pr_AutonomousFlag = _B_TRUE; 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate if (debug & D_PREFIX) { 939*7c478bd9Sstevel@tonic-gate logmsg(LOG_DEBUG, "incoming_prefix_addrconf_process(%s, %s/%u) " 940*7c478bd9Sstevel@tonic-gate "valid %u pref %u\n", 941*7c478bd9Sstevel@tonic-gate pr->pr_physical->pi_name, 942*7c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_prefix, 943*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)), pr->pr_prefix_len, 944*7c478bd9Sstevel@tonic-gate pr->pr_ValidLifetime, pr->pr_PreferredLifetime); 945*7c478bd9Sstevel@tonic-gate } 946*7c478bd9Sstevel@tonic-gate 947*7c478bd9Sstevel@tonic-gate if (pr->pr_state & PR_AUTO) { 948*7c478bd9Sstevel@tonic-gate /* Take the min of the two timeouts by calling it twice */ 949*7c478bd9Sstevel@tonic-gate if (pr->pr_ValidLifetime != 0) 950*7c478bd9Sstevel@tonic-gate timer_schedule(pr->pr_ValidLifetime); 951*7c478bd9Sstevel@tonic-gate if (pr->pr_PreferredLifetime != 0) 952*7c478bd9Sstevel@tonic-gate timer_schedule(pr->pr_PreferredLifetime); 953*7c478bd9Sstevel@tonic-gate } 954*7c478bd9Sstevel@tonic-gate if (pr->pr_kernel_state != pr->pr_state) { 955*7c478bd9Sstevel@tonic-gate /* Log a message when an addrconf prefix goes away */ 956*7c478bd9Sstevel@tonic-gate if ((pr->pr_kernel_state & PR_AUTO) && 957*7c478bd9Sstevel@tonic-gate !(pr->pr_state & PR_AUTO)) { 958*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate logmsg(LOG_WARNING, "Address removed due to zero " 961*7c478bd9Sstevel@tonic-gate "valid lifetime %s\n", 962*7c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, (void *)&pr->pr_address, 963*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf))); 964*7c478bd9Sstevel@tonic-gate } 965*7c478bd9Sstevel@tonic-gate prefix_update_k(pr); 966*7c478bd9Sstevel@tonic-gate } 967*7c478bd9Sstevel@tonic-gate return (_B_TRUE); 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate /* 971*7c478bd9Sstevel@tonic-gate * Process an MTU option received in a router advertisement. 972*7c478bd9Sstevel@tonic-gate */ 973*7c478bd9Sstevel@tonic-gate static void 974*7c478bd9Sstevel@tonic-gate incoming_mtu_opt(struct phyint *pi, uchar_t *opt, 975*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from) 976*7c478bd9Sstevel@tonic-gate { 977*7c478bd9Sstevel@tonic-gate struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt; 978*7c478bd9Sstevel@tonic-gate struct lifreq lifr; 979*7c478bd9Sstevel@tonic-gate uint32_t mtu; 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) { 982*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 983*7c478bd9Sstevel@tonic-gate 984*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 985*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 986*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "mtu option from %s on %s wrong size " 987*7c478bd9Sstevel@tonic-gate "(%d bytes)\n", 988*7c478bd9Sstevel@tonic-gate abuf, pi->pi_name, 989*7c478bd9Sstevel@tonic-gate 8 * (int)mo->nd_opt_mtu_len); 990*7c478bd9Sstevel@tonic-gate return; 991*7c478bd9Sstevel@tonic-gate } 992*7c478bd9Sstevel@tonic-gate mtu = ntohl(mo->nd_opt_mtu_mtu); 993*7c478bd9Sstevel@tonic-gate if (pi->pi_LinkMTU == mtu) 994*7c478bd9Sstevel@tonic-gate return; /* No change */ 995*7c478bd9Sstevel@tonic-gate if (mtu > pi->pi_mtu) { 996*7c478bd9Sstevel@tonic-gate /* Can't exceed physical MTU */ 997*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 1000*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 1001*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "mtu option from %s on %s too large " 1002*7c478bd9Sstevel@tonic-gate "MTU %d - %d\n", abuf, pi->pi_name, mtu, pi->pi_mtu); 1003*7c478bd9Sstevel@tonic-gate return; 1004*7c478bd9Sstevel@tonic-gate } 1005*7c478bd9Sstevel@tonic-gate if (mtu < IPV6_MIN_MTU) { 1006*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 1009*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 1010*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "mtu option from %s on %s too small " 1011*7c478bd9Sstevel@tonic-gate "MTU (%d)\n", abuf, pi->pi_name, mtu); 1012*7c478bd9Sstevel@tonic-gate return; 1013*7c478bd9Sstevel@tonic-gate } 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate pi->pi_LinkMTU = mtu; 1016*7c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 1017*7c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1018*7c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCGLIFLNKINFO, (char *)&lifr) < 0) { 1019*7c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_mtu_opt: SIOCGLIFLNKINFO"); 1020*7c478bd9Sstevel@tonic-gate return; 1021*7c478bd9Sstevel@tonic-gate } 1022*7c478bd9Sstevel@tonic-gate lifr.lifr_ifinfo.lir_maxmtu = pi->pi_LinkMTU; 1023*7c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) { 1024*7c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_mtu_opt: SIOCSLIFLNKINFO"); 1025*7c478bd9Sstevel@tonic-gate return; 1026*7c478bd9Sstevel@tonic-gate } 1027*7c478bd9Sstevel@tonic-gate } 1028*7c478bd9Sstevel@tonic-gate 1029*7c478bd9Sstevel@tonic-gate /* 1030*7c478bd9Sstevel@tonic-gate * Process a source link-layer address option received in a router 1031*7c478bd9Sstevel@tonic-gate * advertisement or solicitation. 1032*7c478bd9Sstevel@tonic-gate */ 1033*7c478bd9Sstevel@tonic-gate static void 1034*7c478bd9Sstevel@tonic-gate incoming_lla_opt(struct phyint *pi, uchar_t *opt, 1035*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from, int isrouter) 1036*7c478bd9Sstevel@tonic-gate { 1037*7c478bd9Sstevel@tonic-gate struct nd_opt_lla *lo = (struct nd_opt_lla *)opt; 1038*7c478bd9Sstevel@tonic-gate struct lifreq lifr; 1039*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 1040*7c478bd9Sstevel@tonic-gate int max_content_len; 1041*7c478bd9Sstevel@tonic-gate 1042*7c478bd9Sstevel@tonic-gate if (pi->pi_hdw_addr_len == 0) 1043*7c478bd9Sstevel@tonic-gate return; 1044*7c478bd9Sstevel@tonic-gate 1045*7c478bd9Sstevel@tonic-gate /* 1046*7c478bd9Sstevel@tonic-gate * Can't remove padding since it is link type specific. 1047*7c478bd9Sstevel@tonic-gate * However, we check against the length of our link-layer 1048*7c478bd9Sstevel@tonic-gate * address. 1049*7c478bd9Sstevel@tonic-gate * Note: assumes that all links have a fixed lengh address. 1050*7c478bd9Sstevel@tonic-gate */ 1051*7c478bd9Sstevel@tonic-gate max_content_len = lo->nd_opt_lla_len * 8 - sizeof (struct nd_opt_hdr); 1052*7c478bd9Sstevel@tonic-gate if (max_content_len < pi->pi_hdw_addr_len || 1053*7c478bd9Sstevel@tonic-gate (max_content_len >= 8 && 1054*7c478bd9Sstevel@tonic-gate max_content_len - 7 > pi->pi_hdw_addr_len)) { 1055*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1056*7c478bd9Sstevel@tonic-gate 1057*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 1058*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 1059*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "lla option from %s on %s too long with bad " 1060*7c478bd9Sstevel@tonic-gate "physaddr length (%d vs. %d bytes)\n", 1061*7c478bd9Sstevel@tonic-gate abuf, pi->pi_name, 1062*7c478bd9Sstevel@tonic-gate max_content_len, pi->pi_hdw_addr_len); 1063*7c478bd9Sstevel@tonic-gate return; 1064*7c478bd9Sstevel@tonic-gate } 1065*7c478bd9Sstevel@tonic-gate 1066*7c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_hdw_len = pi->pi_hdw_addr_len; 1067*7c478bd9Sstevel@tonic-gate bcopy((char *)lo->nd_opt_lla_hdw_addr, 1068*7c478bd9Sstevel@tonic-gate (char *)lifr.lifr_nd.lnr_hdw_addr, 1069*7c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_hdw_len); 1070*7c478bd9Sstevel@tonic-gate 1071*7c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr; 1072*7c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (struct sockaddr_in6)); 1073*7c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 1074*7c478bd9Sstevel@tonic-gate sin6->sin6_addr = from->sin6_addr; 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate /* 1077*7c478bd9Sstevel@tonic-gate * Set IsRouter flag if RA; clear if RS. 1078*7c478bd9Sstevel@tonic-gate */ 1079*7c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_state_create = ND_STALE; 1080*7c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 1081*7c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_state_diff_lla = ND_STALE; 1082*7c478bd9Sstevel@tonic-gate lifr.lifr_nd.lnr_flags = isrouter; 1083*7c478bd9Sstevel@tonic-gate (void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name)); 1084*7c478bd9Sstevel@tonic-gate lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0'; 1085*7c478bd9Sstevel@tonic-gate if (ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr) < 0) { 1086*7c478bd9Sstevel@tonic-gate logperror_pi(pi, "incoming_lla_opt: SIOCLIFSETND"); 1087*7c478bd9Sstevel@tonic-gate return; 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate } 1090*7c478bd9Sstevel@tonic-gate 1091*7c478bd9Sstevel@tonic-gate /* 1092*7c478bd9Sstevel@tonic-gate * Verify the content of the received router advertisement against our 1093*7c478bd9Sstevel@tonic-gate * own configuration as specified in RFC 2461. 1094*7c478bd9Sstevel@tonic-gate */ 1095*7c478bd9Sstevel@tonic-gate static void 1096*7c478bd9Sstevel@tonic-gate verify_ra_consistency(struct phyint *pi, struct nd_router_advert *ra, int len, 1097*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *from) 1098*7c478bd9Sstevel@tonic-gate { 1099*7c478bd9Sstevel@tonic-gate char frombuf[INET6_ADDRSTRLEN]; 1100*7c478bd9Sstevel@tonic-gate struct nd_opt_hdr *opt; 1101*7c478bd9Sstevel@tonic-gate int optlen; 1102*7c478bd9Sstevel@tonic-gate uint_t reachable, retrans; 1103*7c478bd9Sstevel@tonic-gate boolean_t pktflag, myflag; 1104*7c478bd9Sstevel@tonic-gate 1105*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, 1106*7c478bd9Sstevel@tonic-gate frombuf, sizeof (frombuf)); 1107*7c478bd9Sstevel@tonic-gate 1108*7c478bd9Sstevel@tonic-gate if (ra->nd_ra_curhoplimit != 0 && 1109*7c478bd9Sstevel@tonic-gate pi->pi_AdvCurHopLimit != 0 && 1110*7c478bd9Sstevel@tonic-gate ra->nd_ra_curhoplimit != pi->pi_AdvCurHopLimit) { 1111*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent cur hop " 1112*7c478bd9Sstevel@tonic-gate "limit:\n\treceived %d configuration %d\n", 1113*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 1114*7c478bd9Sstevel@tonic-gate ra->nd_ra_curhoplimit, pi->pi_AdvCurHopLimit); 1115*7c478bd9Sstevel@tonic-gate } 1116*7c478bd9Sstevel@tonic-gate 1117*7c478bd9Sstevel@tonic-gate reachable = ntohl(ra->nd_ra_reachable); 1118*7c478bd9Sstevel@tonic-gate if (reachable != 0 && pi->pi_AdvReachableTime != 0 && 1119*7c478bd9Sstevel@tonic-gate reachable != pi->pi_AdvReachableTime) { 1120*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent reachable " 1121*7c478bd9Sstevel@tonic-gate "time:\n\treceived %d configuration %d\n", 1122*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 1123*7c478bd9Sstevel@tonic-gate reachable, pi->pi_AdvReachableTime); 1124*7c478bd9Sstevel@tonic-gate } 1125*7c478bd9Sstevel@tonic-gate 1126*7c478bd9Sstevel@tonic-gate retrans = ntohl(ra->nd_ra_retransmit); 1127*7c478bd9Sstevel@tonic-gate if (retrans != 0 && pi->pi_AdvRetransTimer != 0 && 1128*7c478bd9Sstevel@tonic-gate retrans != pi->pi_AdvRetransTimer) { 1129*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent retransmit " 1130*7c478bd9Sstevel@tonic-gate "timer:\n\treceived %d configuration %d\n", 1131*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 1132*7c478bd9Sstevel@tonic-gate retrans, pi->pi_AdvRetransTimer); 1133*7c478bd9Sstevel@tonic-gate } 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != 0); 1136*7c478bd9Sstevel@tonic-gate myflag = (pi->pi_AdvManagedFlag != 0); 1137*7c478bd9Sstevel@tonic-gate if (pktflag != myflag) { 1138*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent managed " 1139*7c478bd9Sstevel@tonic-gate "flag:\n\treceived %s configuration %s\n", 1140*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 1141*7c478bd9Sstevel@tonic-gate (pktflag ? "ON" : "OFF"), 1142*7c478bd9Sstevel@tonic-gate (myflag ? "ON" : "OFF")); 1143*7c478bd9Sstevel@tonic-gate } 1144*7c478bd9Sstevel@tonic-gate pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != 0); 1145*7c478bd9Sstevel@tonic-gate myflag = (pi->pi_AdvOtherConfigFlag != 0); 1146*7c478bd9Sstevel@tonic-gate if (pktflag != myflag) { 1147*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent other config " 1148*7c478bd9Sstevel@tonic-gate "flag:\n\treceived %s configuration %s\n", 1149*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 1150*7c478bd9Sstevel@tonic-gate (pktflag ? "ON" : "OFF"), 1151*7c478bd9Sstevel@tonic-gate (myflag ? "ON" : "OFF")); 1152*7c478bd9Sstevel@tonic-gate } 1153*7c478bd9Sstevel@tonic-gate 1154*7c478bd9Sstevel@tonic-gate /* Process any options */ 1155*7c478bd9Sstevel@tonic-gate len -= sizeof (struct nd_router_advert); 1156*7c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)&ra[1]; 1157*7c478bd9Sstevel@tonic-gate while (len >= sizeof (struct nd_opt_hdr)) { 1158*7c478bd9Sstevel@tonic-gate optlen = opt->nd_opt_len * 8; 1159*7c478bd9Sstevel@tonic-gate switch (opt->nd_opt_type) { 1160*7c478bd9Sstevel@tonic-gate case ND_OPT_PREFIX_INFORMATION: 1161*7c478bd9Sstevel@tonic-gate verify_prefix_opt(pi, (uchar_t *)opt, frombuf); 1162*7c478bd9Sstevel@tonic-gate break; 1163*7c478bd9Sstevel@tonic-gate case ND_OPT_MTU: 1164*7c478bd9Sstevel@tonic-gate verify_mtu_opt(pi, (uchar_t *)opt, frombuf); 1165*7c478bd9Sstevel@tonic-gate break; 1166*7c478bd9Sstevel@tonic-gate default: 1167*7c478bd9Sstevel@tonic-gate break; 1168*7c478bd9Sstevel@tonic-gate } 1169*7c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + optlen); 1170*7c478bd9Sstevel@tonic-gate len -= optlen; 1171*7c478bd9Sstevel@tonic-gate } 1172*7c478bd9Sstevel@tonic-gate } 1173*7c478bd9Sstevel@tonic-gate 1174*7c478bd9Sstevel@tonic-gate /* 1175*7c478bd9Sstevel@tonic-gate * Verify that the lifetimes and onlink/auto flags are consistent 1176*7c478bd9Sstevel@tonic-gate * with our settings. 1177*7c478bd9Sstevel@tonic-gate */ 1178*7c478bd9Sstevel@tonic-gate static void 1179*7c478bd9Sstevel@tonic-gate verify_prefix_opt(struct phyint *pi, uchar_t *opt, char *frombuf) 1180*7c478bd9Sstevel@tonic-gate { 1181*7c478bd9Sstevel@tonic-gate struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; 1182*7c478bd9Sstevel@tonic-gate int plen; 1183*7c478bd9Sstevel@tonic-gate struct adv_prefix *adv_pr; 1184*7c478bd9Sstevel@tonic-gate uint32_t validtime, preftime; 1185*7c478bd9Sstevel@tonic-gate char prefixbuf[INET6_ADDRSTRLEN]; 1186*7c478bd9Sstevel@tonic-gate int pktflag, myflag; 1187*7c478bd9Sstevel@tonic-gate 1188*7c478bd9Sstevel@tonic-gate if (8 * po->nd_opt_pi_len != sizeof (*po)) { 1189*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA prefix option from %s on %s wrong size " 1190*7c478bd9Sstevel@tonic-gate "(%d bytes)\n", 1191*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 1192*7c478bd9Sstevel@tonic-gate 8 * (int)po->nd_opt_pi_len); 1193*7c478bd9Sstevel@tonic-gate return; 1194*7c478bd9Sstevel@tonic-gate } 1195*7c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) { 1196*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s contains link-local " 1197*7c478bd9Sstevel@tonic-gate "prefix - ignored\n", 1198*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name); 1199*7c478bd9Sstevel@tonic-gate return; 1200*7c478bd9Sstevel@tonic-gate } 1201*7c478bd9Sstevel@tonic-gate plen = po->nd_opt_pi_prefix_len; 1202*7c478bd9Sstevel@tonic-gate adv_pr = adv_prefix_lookup(pi, po->nd_opt_pi_prefix, plen); 1203*7c478bd9Sstevel@tonic-gate if (adv_pr == NULL) 1204*7c478bd9Sstevel@tonic-gate return; 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate /* Ignore prefixes which we do not advertise */ 1207*7c478bd9Sstevel@tonic-gate if (!adv_pr->adv_pr_AdvAutonomousFlag && !adv_pr->adv_pr_AdvOnLinkFlag) 1208*7c478bd9Sstevel@tonic-gate return; 1209*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix, 1210*7c478bd9Sstevel@tonic-gate prefixbuf, sizeof (prefixbuf)); 1211*7c478bd9Sstevel@tonic-gate pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) != 0); 1212*7c478bd9Sstevel@tonic-gate myflag = (adv_pr->adv_pr_AdvAutonomousFlag != 0); 1213*7c478bd9Sstevel@tonic-gate if (pktflag != myflag) { 1214*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, 1215*7c478bd9Sstevel@tonic-gate "RA from %s on %s inconsistent autonumous flag for \n\t" 1216*7c478bd9Sstevel@tonic-gate "prefix %s/%u: received %s configuration %s\n", 1217*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len, 1218*7c478bd9Sstevel@tonic-gate (pktflag ? "ON" : "OFF"), 1219*7c478bd9Sstevel@tonic-gate (myflag ? "ON" : "OFF")); 1220*7c478bd9Sstevel@tonic-gate } 1221*7c478bd9Sstevel@tonic-gate 1222*7c478bd9Sstevel@tonic-gate pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) != 0); 1223*7c478bd9Sstevel@tonic-gate myflag = (adv_pr->adv_pr_AdvOnLinkFlag != 0); 1224*7c478bd9Sstevel@tonic-gate if (pktflag != myflag) { 1225*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent on link flag " 1226*7c478bd9Sstevel@tonic-gate "for \n\tprefix %s/%u: received %s configuration %s\n", 1227*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len, 1228*7c478bd9Sstevel@tonic-gate (pktflag ? "ON" : "OFF"), 1229*7c478bd9Sstevel@tonic-gate (myflag ? "ON" : "OFF")); 1230*7c478bd9Sstevel@tonic-gate } 1231*7c478bd9Sstevel@tonic-gate validtime = ntohl(po->nd_opt_pi_valid_time); 1232*7c478bd9Sstevel@tonic-gate preftime = ntohl(po->nd_opt_pi_preferred_time); 1233*7c478bd9Sstevel@tonic-gate 1234*7c478bd9Sstevel@tonic-gate /* 1235*7c478bd9Sstevel@tonic-gate * Take into account variation for lifetimes decrementing 1236*7c478bd9Sstevel@tonic-gate * in real time. Allow +/- 10 percent and +/- 10 seconds. 1237*7c478bd9Sstevel@tonic-gate */ 1238*7c478bd9Sstevel@tonic-gate #define LOWER_LIMIT(val) ((val) - (val)/10 - 10) 1239*7c478bd9Sstevel@tonic-gate #define UPPER_LIMIT(val) ((val) + (val)/10 + 10) 1240*7c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidRealTime) { 1241*7c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvValidExpiration > 0 && 1242*7c478bd9Sstevel@tonic-gate (validtime < 1243*7c478bd9Sstevel@tonic-gate LOWER_LIMIT(adv_pr->adv_pr_AdvValidExpiration) || 1244*7c478bd9Sstevel@tonic-gate validtime > 1245*7c478bd9Sstevel@tonic-gate UPPER_LIMIT(adv_pr->adv_pr_AdvValidExpiration))) { 1246*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent valid " 1247*7c478bd9Sstevel@tonic-gate "lifetime for\n\tprefix %s/%u: received %d " 1248*7c478bd9Sstevel@tonic-gate "configuration %d\n", 1249*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, 1250*7c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len, 1251*7c478bd9Sstevel@tonic-gate validtime, adv_pr->adv_pr_AdvValidExpiration); 1252*7c478bd9Sstevel@tonic-gate } 1253*7c478bd9Sstevel@tonic-gate } else { 1254*7c478bd9Sstevel@tonic-gate if (validtime != adv_pr->adv_pr_AdvValidLifetime) { 1255*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent valid " 1256*7c478bd9Sstevel@tonic-gate "lifetime for\n\tprefix %s/%u: received %d " 1257*7c478bd9Sstevel@tonic-gate "configuration %d\n", 1258*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, 1259*7c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len, 1260*7c478bd9Sstevel@tonic-gate validtime, adv_pr->adv_pr_AdvValidLifetime); 1261*7c478bd9Sstevel@tonic-gate } 1262*7c478bd9Sstevel@tonic-gate } 1263*7c478bd9Sstevel@tonic-gate 1264*7c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredRealTime) { 1265*7c478bd9Sstevel@tonic-gate if (adv_pr->adv_pr_AdvPreferredExpiration > 0 && 1266*7c478bd9Sstevel@tonic-gate (preftime < 1267*7c478bd9Sstevel@tonic-gate LOWER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration) || 1268*7c478bd9Sstevel@tonic-gate preftime > 1269*7c478bd9Sstevel@tonic-gate UPPER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration))) { 1270*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent " 1271*7c478bd9Sstevel@tonic-gate "preferred lifetime for\n\tprefix %s/%u: " 1272*7c478bd9Sstevel@tonic-gate "received %d configuration %d\n", 1273*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, 1274*7c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len, 1275*7c478bd9Sstevel@tonic-gate preftime, adv_pr->adv_pr_AdvPreferredExpiration); 1276*7c478bd9Sstevel@tonic-gate } 1277*7c478bd9Sstevel@tonic-gate } else { 1278*7c478bd9Sstevel@tonic-gate if (preftime != adv_pr->adv_pr_AdvPreferredLifetime) { 1279*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent " 1280*7c478bd9Sstevel@tonic-gate "preferred lifetime for\n\tprefix %s/%u: " 1281*7c478bd9Sstevel@tonic-gate "received %d configuration %d\n", 1282*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, prefixbuf, 1283*7c478bd9Sstevel@tonic-gate adv_pr->adv_pr_prefix_len, 1284*7c478bd9Sstevel@tonic-gate preftime, adv_pr->adv_pr_AdvPreferredLifetime); 1285*7c478bd9Sstevel@tonic-gate } 1286*7c478bd9Sstevel@tonic-gate } 1287*7c478bd9Sstevel@tonic-gate } 1288*7c478bd9Sstevel@tonic-gate 1289*7c478bd9Sstevel@tonic-gate /* 1290*7c478bd9Sstevel@tonic-gate * Verify the received MTU against our own configuration. 1291*7c478bd9Sstevel@tonic-gate */ 1292*7c478bd9Sstevel@tonic-gate static void 1293*7c478bd9Sstevel@tonic-gate verify_mtu_opt(struct phyint *pi, uchar_t *opt, char *frombuf) 1294*7c478bd9Sstevel@tonic-gate { 1295*7c478bd9Sstevel@tonic-gate struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt; 1296*7c478bd9Sstevel@tonic-gate uint32_t mtu; 1297*7c478bd9Sstevel@tonic-gate 1298*7c478bd9Sstevel@tonic-gate if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) { 1299*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "mtu option from %s on %s wrong size " 1300*7c478bd9Sstevel@tonic-gate "(%d bytes)\n", 1301*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 1302*7c478bd9Sstevel@tonic-gate 8 * (int)mo->nd_opt_mtu_len); 1303*7c478bd9Sstevel@tonic-gate return; 1304*7c478bd9Sstevel@tonic-gate } 1305*7c478bd9Sstevel@tonic-gate mtu = ntohl(mo->nd_opt_mtu_mtu); 1306*7c478bd9Sstevel@tonic-gate if (pi->pi_AdvLinkMTU != 0 && 1307*7c478bd9Sstevel@tonic-gate pi->pi_AdvLinkMTU != mtu) { 1308*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "RA from %s on %s inconsistent MTU: " 1309*7c478bd9Sstevel@tonic-gate "received %d configuration %d\n", 1310*7c478bd9Sstevel@tonic-gate frombuf, pi->pi_name, 1311*7c478bd9Sstevel@tonic-gate mtu, pi->pi_AdvLinkMTU); 1312*7c478bd9Sstevel@tonic-gate } 1313*7c478bd9Sstevel@tonic-gate } 1314*7c478bd9Sstevel@tonic-gate 1315*7c478bd9Sstevel@tonic-gate /* 1316*7c478bd9Sstevel@tonic-gate * Verify that all options have a non-zero length and that 1317*7c478bd9Sstevel@tonic-gate * the options fit within the total length of the packet (optlen). 1318*7c478bd9Sstevel@tonic-gate */ 1319*7c478bd9Sstevel@tonic-gate static boolean_t 1320*7c478bd9Sstevel@tonic-gate verify_opt_len(struct nd_opt_hdr *opt, int optlen, 1321*7c478bd9Sstevel@tonic-gate struct phyint *pi, struct sockaddr_in6 *from) 1322*7c478bd9Sstevel@tonic-gate { 1323*7c478bd9Sstevel@tonic-gate while (optlen > 0) { 1324*7c478bd9Sstevel@tonic-gate if (opt->nd_opt_len == 0) { 1325*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1326*7c478bd9Sstevel@tonic-gate 1327*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 1328*7c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 1329*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 1330*7c478bd9Sstevel@tonic-gate 1331*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Zero length option type 0x%x " 1332*7c478bd9Sstevel@tonic-gate "from %s on %s\n", 1333*7c478bd9Sstevel@tonic-gate opt->nd_opt_type, abuf, pi->pi_name); 1334*7c478bd9Sstevel@tonic-gate return (_B_FALSE); 1335*7c478bd9Sstevel@tonic-gate } 1336*7c478bd9Sstevel@tonic-gate optlen -= 8 * opt->nd_opt_len; 1337*7c478bd9Sstevel@tonic-gate if (optlen < 0) { 1338*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET6, 1341*7c478bd9Sstevel@tonic-gate (void *)&from->sin6_addr, 1342*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 1343*7c478bd9Sstevel@tonic-gate 1344*7c478bd9Sstevel@tonic-gate logmsg(LOG_INFO, "Too large option: type 0x%x len %u " 1345*7c478bd9Sstevel@tonic-gate "from %s on %s\n", 1346*7c478bd9Sstevel@tonic-gate opt->nd_opt_type, opt->nd_opt_len, 1347*7c478bd9Sstevel@tonic-gate abuf, pi->pi_name); 1348*7c478bd9Sstevel@tonic-gate return (_B_FALSE); 1349*7c478bd9Sstevel@tonic-gate } 1350*7c478bd9Sstevel@tonic-gate opt = (struct nd_opt_hdr *)((char *)opt + 1351*7c478bd9Sstevel@tonic-gate 8 * opt->nd_opt_len); 1352*7c478bd9Sstevel@tonic-gate } 1353*7c478bd9Sstevel@tonic-gate return (_B_TRUE); 1354*7c478bd9Sstevel@tonic-gate } 1355