Home | History | Annotate | Download | only in in.ndpd
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include "defs.h"
     28 #include "tables.h"
     29 
     30 #include <sys/sysmacros.h>
     31 
     32 #include <dhcpagent_ipc.h>
     33 #include <dhcpagent_util.h>
     34 
     35 static boolean_t verify_opt_len(struct nd_opt_hdr *opt, int optlen,
     36 		    struct phyint *pi, struct sockaddr_in6 *from);
     37 
     38 static void	incoming_rs(struct phyint *pi, struct nd_router_solicit *rs,
     39 		    int len, struct sockaddr_in6 *from);
     40 
     41 void		incoming_ra(struct phyint *pi, struct nd_router_advert *ra,
     42 		    int len, struct sockaddr_in6 *from, boolean_t loopback);
     43 static void	incoming_prefix_opt(struct phyint *pi, uchar_t *opt,
     44 		    struct sockaddr_in6 *from, boolean_t loopback);
     45 static void	incoming_prefix_onlink(struct phyint *pi, uchar_t *opt);
     46 void		incoming_prefix_onlink_process(struct prefix *pr,
     47 		    uchar_t *opt);
     48 static void	incoming_prefix_stateful(struct phyint *, uchar_t *);
     49 static boolean_t	incoming_prefix_addrconf(struct phyint *pi,
     50 		    uchar_t *opt, struct sockaddr_in6 *from,
     51 		    boolean_t loopback);
     52 boolean_t	incoming_prefix_addrconf_process(struct phyint *pi,
     53 		    struct prefix *pr, uchar_t *opt,
     54 		    struct sockaddr_in6 *from, boolean_t loopback,
     55 		    boolean_t new_prefix);
     56 static void	incoming_mtu_opt(struct phyint *pi, uchar_t *opt,
     57 		    struct sockaddr_in6 *from);
     58 static void	incoming_lla_opt(struct phyint *pi, uchar_t *opt,
     59 		    struct sockaddr_in6 *from, int isrouter);
     60 
     61 static void	verify_ra_consistency(struct phyint *pi,
     62 		    struct nd_router_advert *ra,
     63 		    int len, struct sockaddr_in6 *from);
     64 static void	verify_prefix_opt(struct phyint *pi, uchar_t *opt,
     65 		    char *frombuf);
     66 static void	verify_mtu_opt(struct phyint *pi, uchar_t *opt,
     67 		    char *frombuf);
     68 
     69 static void	update_ra_flag(const struct phyint *pi,
     70 		    const struct sockaddr_in6 *from, int isrouter);
     71 
     72 /*
     73  * Return a pointer to the specified option buffer.
     74  * If not found return NULL.
     75  */
     76 static void *
     77 find_ancillary(struct msghdr *msg, int cmsg_type)
     78 {
     79 	struct cmsghdr *cmsg;
     80 
     81 	for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
     82 	    cmsg = CMSG_NXTHDR(msg, cmsg)) {
     83 		if (cmsg->cmsg_level == IPPROTO_IPV6 &&
     84 		    cmsg->cmsg_type == cmsg_type) {
     85 			return (CMSG_DATA(cmsg));
     86 		}
     87 	}
     88 	return (NULL);
     89 }
     90 
     91 void
     92 in_data(struct phyint *pi)
     93 {
     94 	struct sockaddr_in6 from;
     95 	struct icmp6_hdr *icmp;
     96 	struct nd_router_solicit *rs;
     97 	struct nd_router_advert *ra;
     98 	static uint64_t in_packet[(IP_MAXPACKET + 1)/8];
     99 	static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8];
    100 	int len;
    101 	char abuf[INET6_ADDRSTRLEN];
    102 	const char *msgbuf;
    103 	struct msghdr msg;
    104 	struct iovec iov;
    105 	uchar_t *opt;
    106 	uint_t hoplimit;
    107 
    108 	iov.iov_base = (char *)in_packet;
    109 	iov.iov_len = sizeof (in_packet);
    110 	msg.msg_iov = &iov;
    111 	msg.msg_iovlen = 1;
    112 	msg.msg_name = (struct sockaddr *)&from;
    113 	msg.msg_namelen = sizeof (from);
    114 	msg.msg_control = ancillary_data;
    115 	msg.msg_controllen = sizeof (ancillary_data);
    116 
    117 	if ((len = recvmsg(pi->pi_sock, &msg, 0)) < 0) {
    118 		logperror_pi(pi, "in_data: recvfrom");
    119 		return;
    120 	}
    121 	if (len == 0)
    122 		return;
    123 
    124 	if (inet_ntop(AF_INET6, (void *)&from.sin6_addr,
    125 	    abuf, sizeof (abuf)) == NULL)
    126 		msgbuf = "Unspecified Router";
    127 	else
    128 		msgbuf = abuf;
    129 
    130 	/* Ignore packets > 64k or control buffers that don't fit */
    131 	if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
    132 		if (debug & D_PKTBAD) {
    133 			logmsg(LOG_DEBUG, "Truncated message: msg_flags 0x%x "
    134 			    "from %s\n", msg.msg_flags, msgbuf);
    135 		}
    136 		return;
    137 	}
    138 
    139 	icmp = (struct icmp6_hdr *)in_packet;
    140 
    141 	if (len < ICMP6_MINLEN) {
    142 		logmsg(LOG_INFO, "Too short ICMP packet: %d bytes "
    143 		    "from %s on %s\n",
    144 		    len, msgbuf, pi->pi_name);
    145 		return;
    146 	}
    147 
    148 	opt = find_ancillary(&msg, IPV6_HOPLIMIT);
    149 	if (opt == NULL) {
    150 		/* Unknown hoplimit - must drop */
    151 		logmsg(LOG_INFO, "Unknown hop limit from %s on %s\n",
    152 		    msgbuf, pi->pi_name);
    153 		return;
    154 	}
    155 	hoplimit = *(uint_t *)opt;
    156 	opt = find_ancillary(&msg, IPV6_RTHDR);
    157 	if (opt != NULL) {
    158 		/* Can't allow routing headers in ND messages */
    159 		logmsg(LOG_INFO, "ND message with routing header "
    160 		    "from %s on %s\n",
    161 		    msgbuf, pi->pi_name);
    162 		return;
    163 	}
    164 	switch (icmp->icmp6_type) {
    165 	case ND_ROUTER_SOLICIT:
    166 		if (!pi->pi_AdvSendAdvertisements)
    167 			return;
    168 		if (pi->pi_flags & IFF_NORTEXCH) {
    169 			if (debug & D_PKTIN) {
    170 				logmsg(LOG_DEBUG, "Ignore received RS packet "
    171 				    "on %s (no route exchange on interface)\n",
    172 				    pi->pi_name);
    173 			}
    174 			return;
    175 		}
    176 
    177 		/*
    178 		 * Assumes that the kernel has verified the AH (if present)
    179 		 * and the ICMP checksum.
    180 		 */
    181 		if (hoplimit != IPV6_MAX_HOPS) {
    182 			logmsg(LOG_DEBUG, "RS hop limit: %d from %s on %s\n",
    183 			    hoplimit, msgbuf, pi->pi_name);
    184 			return;
    185 		}
    186 
    187 		if (icmp->icmp6_code != 0) {
    188 			logmsg(LOG_INFO, "RS code: %d from %s on %s\n",
    189 			    icmp->icmp6_code, msgbuf, pi->pi_name);
    190 			return;
    191 		}
    192 
    193 		if (len < sizeof (struct nd_router_solicit)) {
    194 			logmsg(LOG_INFO, "RS too short: %d bytes "
    195 			    "from %s on %s\n",
    196 			    len, msgbuf, pi->pi_name);
    197 			return;
    198 		}
    199 		rs = (struct nd_router_solicit *)icmp;
    200 		if (len > sizeof (struct nd_router_solicit)) {
    201 			if (!verify_opt_len((struct nd_opt_hdr *)&rs[1],
    202 			    len - sizeof (struct nd_router_solicit), pi, &from))
    203 				return;
    204 		}
    205 		if (debug & D_PKTIN) {
    206 			print_route_sol("Received valid solicit from ", pi,
    207 			    rs, len, &from);
    208 		}
    209 		incoming_rs(pi, rs, len, &from);
    210 		break;
    211 
    212 	case ND_ROUTER_ADVERT:
    213 		if (IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr)) {
    214 			/*
    215 			 * Router advt. must have address!
    216 			 * Logging the news and returning.
    217 			 */
    218 			logmsg(LOG_DEBUG,
    219 			    "Router's address unspecified in advertisement\n");
    220 			return;
    221 		}
    222 		if (pi->pi_flags & IFF_NORTEXCH) {
    223 			if (debug & D_PKTIN) {
    224 				logmsg(LOG_DEBUG, "Ignore received RA packet "
    225 				    "on %s (no route exchange on interface)\n",
    226 				    pi->pi_name);
    227 			}
    228 			return;
    229 		}
    230 
    231 		/*
    232 		 * Assumes that the kernel has verified the AH (if present)
    233 		 * and the ICMP checksum.
    234 		 */
    235 		if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
    236 			logmsg(LOG_DEBUG, "RA from %s - not link local on %s\n",
    237 			    msgbuf, pi->pi_name);
    238 			return;
    239 		}
    240 
    241 		if (hoplimit != IPV6_MAX_HOPS) {
    242 			logmsg(LOG_INFO, "RA hop limit: %d from %s on %s\n",
    243 			    hoplimit, msgbuf, pi->pi_name);
    244 			return;
    245 		}
    246 
    247 		if (icmp->icmp6_code != 0) {
    248 			logmsg(LOG_INFO, "RA code: %d from %s on %s\n",
    249 			    icmp->icmp6_code, msgbuf, pi->pi_name);
    250 			return;
    251 		}
    252 
    253 		if (len < sizeof (struct nd_router_advert)) {
    254 			logmsg(LOG_INFO, "RA too short: %d bytes "
    255 			    "from %s on %s\n",
    256 			    len, msgbuf, pi->pi_name);
    257 			return;
    258 		}
    259 		ra = (struct nd_router_advert *)icmp;
    260 		if (len > sizeof (struct nd_router_advert)) {
    261 			if (!verify_opt_len((struct nd_opt_hdr *)&ra[1],
    262 			    len - sizeof (struct nd_router_advert), pi, &from))
    263 				return;
    264 		}
    265 		if (debug & D_PKTIN) {
    266 			print_route_adv("Received valid advert from ", pi,
    267 			    ra, len, &from);
    268 		}
    269 		if (pi->pi_AdvSendAdvertisements)
    270 			verify_ra_consistency(pi, ra, len, &from);
    271 		else
    272 			incoming_ra(pi, ra, len, &from, _B_FALSE);
    273 		break;
    274 	}
    275 }
    276 
    277 /*
    278  * Process a received router solicitation.
    279  * Check for source link-layer address option and check if it
    280  * is time to advertise.
    281  */
    282 static void
    283 incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, int len,
    284     struct sockaddr_in6 *from)
    285 {
    286 	struct nd_opt_hdr *opt;
    287 	int optlen;
    288 
    289 	/* Process any options */
    290 	len -= sizeof (struct nd_router_solicit);
    291 	opt = (struct nd_opt_hdr *)&rs[1];
    292 	while (len >= sizeof (struct nd_opt_hdr)) {
    293 		optlen = opt->nd_opt_len * 8;
    294 		switch (opt->nd_opt_type) {
    295 		case ND_OPT_SOURCE_LINKADDR:
    296 			incoming_lla_opt(pi, (uchar_t *)opt,
    297 			    from, NDF_ISROUTER_OFF);
    298 			break;
    299 		default:
    300 			break;
    301 		}
    302 		opt = (struct nd_opt_hdr *)((char *)opt + optlen);
    303 		len -= optlen;
    304 	}
    305 	/* Simple algorithm: treat unicast and multicast RSs the same */
    306 	check_to_advertise(pi, RECEIVED_SOLICIT);
    307 }
    308 
    309 /*
    310  * Start up DHCPv6 on a given physical interface.  Does not wait for a message
    311  * to be returned from the daemon.
    312  */
    313 void
    314 start_dhcp(struct phyint *pi)
    315 {
    316 	dhcp_ipc_request_t	*request;
    317 	dhcp_ipc_reply_t	*reply	= NULL;
    318 	int			error;
    319 	int			type;
    320 
    321 	if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) {
    322 		logmsg(LOG_ERR, "start_dhcp: unable to start %s\n",
    323 		    DHCP_AGENT_PATH);
    324 		/* make sure we try again next time there's a chance */
    325 		pi->pi_ra_flags &= ~ND_RA_FLAG_MANAGED & ~ND_RA_FLAG_OTHER;
    326 		return;
    327 	}
    328 
    329 	type = (pi->pi_ra_flags & ND_RA_FLAG_MANAGED) ? DHCP_START :
    330 	    DHCP_INFORM;
    331 
    332 	request = dhcp_ipc_alloc_request(type | DHCP_V6, pi->pi_name, NULL, 0,
    333 	    DHCP_TYPE_NONE);
    334 	if (request == NULL) {
    335 		logmsg(LOG_ERR, "start_dhcp: out of memory\n");
    336 		/* make sure we try again next time there's a chance */
    337 		pi->pi_ra_flags &= ~ND_RA_FLAG_MANAGED & ~ND_RA_FLAG_OTHER;
    338 		return;
    339 	}
    340 
    341 	error = dhcp_ipc_make_request(request, &reply, 0);
    342 	free(request);
    343 	if (error != 0) {
    344 		logmsg(LOG_ERR, "start_dhcp: err: %s: %s\n", pi->pi_name,
    345 		    dhcp_ipc_strerror(error));
    346 		return;
    347 	}
    348 
    349 	error = reply->return_code;
    350 	free(reply);
    351 
    352 	/*
    353 	 * Timeout is considered to be "success" because we don't wait for DHCP
    354 	 * to do its exchange.
    355 	 */
    356 	if (error != DHCP_IPC_SUCCESS && error != DHCP_IPC_E_RUNNING &&
    357 	    error != DHCP_IPC_E_TIMEOUT) {
    358 		logmsg(LOG_ERR, "start_dhcp: ret: %s: %s\n", pi->pi_name,
    359 		    dhcp_ipc_strerror(error));
    360 		return;
    361 	}
    362 }
    363 
    364 /*
    365  * Process a received router advertisement.
    366  * Called both when packets arrive as well as when we send RAs.
    367  * In the latter case 'loopback' is set.
    368  */
    369 void
    370 incoming_ra(struct phyint *pi, struct nd_router_advert *ra, int len,
    371     struct sockaddr_in6 *from, boolean_t loopback)
    372 {
    373 	struct nd_opt_hdr *opt;
    374 	int optlen;
    375 	struct lifreq lifr;
    376 	boolean_t set_needed = _B_FALSE;
    377 	struct router *dr;
    378 	uint16_t router_lifetime;
    379 	uint_t reachable, retrans;
    380 	boolean_t reachable_time_changed = _B_FALSE;
    381 	boolean_t slla_opt_present	 = _B_FALSE;
    382 
    383 	if (no_loopback && loopback)
    384 		return;
    385 
    386 	/*
    387 	 * If the interface is FAILED or INACTIVE or OFFLINE, don't
    388 	 * create any addresses on them. in.mpathd assumes that no new
    389 	 * addresses will appear on these. This implies that we
    390 	 * won't create any new prefixes advertised by the router
    391 	 * on FAILED/INACTIVE/OFFLINE interfaces. When the state changes,
    392 	 * the next RA will create the prefix on this interface.
    393 	 */
    394 	if (pi->pi_flags & (IFF_FAILED|IFF_INACTIVE|IFF_OFFLINE))
    395 		return;
    396 
    397 	(void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
    398 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
    399 	if (ioctl(pi->pi_sock, SIOCGLIFLNKINFO, (char *)&lifr) < 0) {
    400 		if (errno == ENXIO)
    401 			return;
    402 		logperror_pi(pi, "incoming_ra: SIOCGLIFLNKINFO");
    403 		return;
    404 	}
    405 	if (ra->nd_ra_curhoplimit != CURHOP_UNSPECIFIED &&
    406 	    ra->nd_ra_curhoplimit != pi->pi_CurHopLimit) {
    407 		pi->pi_CurHopLimit = ra->nd_ra_curhoplimit;
    408 
    409 		lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit;
    410 		set_needed = _B_TRUE;
    411 	}
    412 
    413 	reachable = ntohl(ra->nd_ra_reachable);
    414 	if (reachable != 0 &&
    415 	    reachable != pi->pi_BaseReachableTime) {
    416 		pi->pi_BaseReachableTime = reachable;
    417 		reachable_time_changed = _B_TRUE;
    418 	}
    419 
    420 	if (pi->pi_reach_time_since_random < MIN_REACH_RANDOM_INTERVAL ||
    421 	    reachable_time_changed) {
    422 		phyint_reach_random(pi, _B_FALSE);
    423 		set_needed = _B_TRUE;
    424 	}
    425 	lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime;
    426 
    427 	retrans = ntohl(ra->nd_ra_retransmit);
    428 	if (retrans != 0 &&
    429 	    pi->pi_RetransTimer != retrans) {
    430 		pi->pi_RetransTimer = retrans;
    431 		lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer;
    432 		set_needed = _B_TRUE;
    433 	}
    434 
    435 	if (set_needed) {
    436 		if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) {
    437 			logperror_pi(pi, "incoming_ra: SIOCSLIFLNKINFO");
    438 			return;
    439 		}
    440 	}
    441 
    442 	/*
    443 	 * If the "managed" flag is set, then just assume that the "other" flag
    444 	 * is set as well.  It's not legal to get addresses alone without
    445 	 * getting other data.
    446 	 */
    447 	if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
    448 		ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
    449 
    450 	/*
    451 	 * If either the "managed" or "other" bits have turned on, then it's
    452 	 * now time to invoke DHCP.  If only the "other" bit is set, then don't
    453 	 * get addresses via DHCP; only "other" data.  If "managed" is set,
    454 	 * then we must always get both addresses and "other" data.
    455 	 */
    456 	if (pi->pi_StatefulAddrConf &&
    457 	    (ra->nd_ra_flags_reserved & ~pi->pi_ra_flags &
    458 	    (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))) {
    459 		if (debug & D_DHCP) {
    460 			logmsg(LOG_DEBUG,
    461 			    "incoming_ra: trigger dhcp %s on %s\n",
    462 			    (ra->nd_ra_flags_reserved & ~pi->pi_ra_flags &
    463 				ND_RA_FLAG_MANAGED) ? "MANAGED" : "OTHER",
    464 			    pi->pi_name);
    465 		}
    466 		pi->pi_ra_flags |= ra->nd_ra_flags_reserved;
    467 		start_dhcp(pi);
    468 	}
    469 
    470 	/* Skip default router code if sent from ourselves */
    471 	if (!loopback) {
    472 		/* Find and update or add default router in list */
    473 		dr = router_lookup(pi, from->sin6_addr);
    474 		router_lifetime = ntohs(ra->nd_ra_router_lifetime);
    475 		if (dr == NULL) {
    476 			if (router_lifetime != 0) {
    477 				dr = router_create(pi, from->sin6_addr,
    478 				    MILLISEC * router_lifetime);
    479 				timer_schedule(dr->dr_lifetime);
    480 			}
    481 		} else {
    482 			dr->dr_lifetime = MILLISEC * router_lifetime;
    483 			if (dr->dr_lifetime != 0)
    484 				timer_schedule(dr->dr_lifetime);
    485 			if ((dr->dr_lifetime != 0 && !dr->dr_inkernel) ||
    486 			    (dr->dr_lifetime == 0 && dr->dr_inkernel))
    487 				router_update_k(dr);
    488 		}
    489 	}
    490 	/* Process any options */
    491 	len -= sizeof (struct nd_router_advert);
    492 	opt = (struct nd_opt_hdr *)&ra[1];
    493 	while (len >= sizeof (struct nd_opt_hdr)) {
    494 		optlen = opt->nd_opt_len * 8;
    495 		switch (opt->nd_opt_type) {
    496 		case ND_OPT_PREFIX_INFORMATION:
    497 			incoming_prefix_opt(pi, (uchar_t *)opt, from,
    498 			    loopback);
    499 			break;
    500 		case ND_OPT_MTU:
    501 			incoming_mtu_opt(pi, (uchar_t *)opt, from);
    502 			break;
    503 		case ND_OPT_SOURCE_LINKADDR:
    504 			/* skip lla option if sent from ourselves! */
    505 			if (!loopback) {
    506 				incoming_lla_opt(pi, (uchar_t *)opt,
    507 				    from, NDF_ISROUTER_ON);
    508 				slla_opt_present = _B_TRUE;
    509 			}
    510 			break;
    511 		default:
    512 			break;
    513 		}
    514 		opt = (struct nd_opt_hdr *)((char *)opt + optlen);
    515 		len -= optlen;
    516 	}
    517 	if (!loopback && !slla_opt_present)
    518 		update_ra_flag(pi, from, NDF_ISROUTER_ON);
    519 	/* Stop sending solicitations */
    520 	check_to_solicit(pi, SOLICIT_DONE);
    521 }
    522 
    523 /*
    524  * Process a received prefix option.
    525  * Unless addrconf is turned off we process both the addrconf and the
    526  * onlink aspects of the prefix option.
    527  *
    528  * Note that when a flag (onlink or auto) is turned off we do nothing -
    529  * the prefix will time out.
    530  */
    531 static void
    532 incoming_prefix_opt(struct phyint *pi, uchar_t *opt,
    533     struct sockaddr_in6 *from, boolean_t loopback)
    534 {
    535 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
    536 	boolean_t	good_prefix = _B_TRUE;
    537 
    538 	if (8 * po->nd_opt_pi_len != sizeof (*po)) {
    539 		char abuf[INET6_ADDRSTRLEN];
    540 
    541 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
    542 		    abuf, sizeof (abuf));
    543 		logmsg(LOG_INFO, "prefix option from %s on %s wrong size "
    544 		    "(%d bytes)\n",
    545 		    abuf, pi->pi_name,
    546 		    8 * (int)po->nd_opt_pi_len);
    547 		return;
    548 	}
    549 	if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) {
    550 		char abuf[INET6_ADDRSTRLEN];
    551 
    552 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
    553 		    abuf, sizeof (abuf));
    554 		logmsg(LOG_INFO, "RA from %s on %s contains link-local prefix "
    555 		    "- ignored\n",
    556 		    abuf, pi->pi_name);
    557 		return;
    558 	}
    559 	if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) &&
    560 	    pi->pi_StatelessAddrConf) {
    561 		good_prefix = incoming_prefix_addrconf(pi, opt, from, loopback);
    562 	}
    563 	if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) &&
    564 	    good_prefix) {
    565 		incoming_prefix_onlink(pi, opt);
    566 	}
    567 	if (pi->pi_StatefulAddrConf)
    568 		incoming_prefix_stateful(pi, opt);
    569 }
    570 
    571 /*
    572  * Process prefix options with the onlink flag set.
    573  *
    574  * If there are no routers ndpd will add an onlink
    575  * default route which will allow communication
    576  * between neighbors.
    577  *
    578  * This function needs to loop to find the same prefix multiple times
    579  * as if a failover happened earlier, the addresses belonging to
    580  * a different interface may be found here on this interface.
    581  */
    582 static void
    583 incoming_prefix_onlink(struct phyint *pi, uchar_t *opt)
    584 {
    585 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
    586 	int plen;
    587 	struct prefix *pr;
    588 	uint32_t validtime;	/* Without 2 hour rule */
    589 	boolean_t found_one = _B_FALSE;
    590 
    591 	plen = po->nd_opt_pi_prefix_len;
    592 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
    593 		if (pr->pr_prefix_len == plen &&
    594 		    prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) {
    595 			/* Exclude static prefixes */
    596 			if (pr->pr_state & PR_STATIC)
    597 				continue;
    598 			found_one = _B_TRUE;
    599 			incoming_prefix_onlink_process(pr, opt);
    600 		}
    601 	}
    602 
    603 	validtime = ntohl(po->nd_opt_pi_valid_time);
    604 	/*
    605 	 * If we have found a matching prefix already or validtime
    606 	 * is zero, we have nothing to do.
    607 	 */
    608 	if (validtime == 0 || found_one)
    609 		return;
    610 	pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0);
    611 	if (pr == NULL)
    612 		return;
    613 	incoming_prefix_onlink_process(pr, opt);
    614 }
    615 
    616 void
    617 incoming_prefix_onlink_process(struct prefix *pr, uchar_t *opt)
    618 {
    619 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
    620 	uint32_t validtime;	/* Without 2 hour rule */
    621 	char abuf[INET6_ADDRSTRLEN];
    622 
    623 	validtime = ntohl(po->nd_opt_pi_valid_time);
    624 	if (validtime != 0)
    625 		pr->pr_state |= PR_ONLINK;
    626 	else
    627 		pr->pr_state &= ~PR_ONLINK;
    628 
    629 	/*
    630 	 * Convert from seconds to milliseconds avoiding overflow.
    631 	 * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1
    632 	 * (4 billion seconds - about 130 years) we will in fact time
    633 	 * out the prefix after 4 billion milliseconds - 46 days).
    634 	 * Thus the longest lifetime (apart from infinity) is 46 days.
    635 	 * Note that this ensures that PREFIX_INFINITY still means "forever".
    636 	 */
    637 	if (pr->pr_flags & IFF_TEMPORARY) {
    638 		pr->pr_OnLinkLifetime = pr->pr_ValidLifetime;
    639 	} else {
    640 		if (validtime >= PREFIX_INFINITY / MILLISEC)
    641 			pr->pr_OnLinkLifetime = PREFIX_INFINITY - 1;
    642 		else
    643 			pr->pr_OnLinkLifetime = validtime * MILLISEC;
    644 	}
    645 	pr->pr_OnLinkFlag = _B_TRUE;
    646 	if (debug & (D_PREFIX|D_TMP)) {
    647 		logmsg(LOG_DEBUG, "incoming_prefix_onlink_process(%s, %s/%u) "
    648 		    "onlink %u state 0x%x, kstate 0x%x\n",
    649 		    pr->pr_name, inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
    650 		    abuf, sizeof (abuf)), pr->pr_prefix_len,
    651 		    pr->pr_OnLinkLifetime, pr->pr_state, pr->pr_kernel_state);
    652 	}
    653 
    654 	if (pr->pr_kernel_state != pr->pr_state) {
    655 		prefix_update_k(pr);
    656 	}
    657 
    658 	if (pr->pr_OnLinkLifetime != 0)
    659 		timer_schedule(pr->pr_OnLinkLifetime);
    660 }
    661 
    662 /*
    663  * Process all prefix options by locating the DHCPv6-configured interfaces, and
    664  * applying the netmasks as needed.
    665  */
    666 static void
    667 incoming_prefix_stateful(struct phyint *pi, uchar_t *opt)
    668 {
    669 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
    670 	struct prefix *pr;
    671 	boolean_t foundpref;
    672 	char abuf[INET6_ADDRSTRLEN];
    673 
    674 	/* Make sure it's a valid prefix. */
    675 	if (ntohl(po->nd_opt_pi_valid_time) == 0) {
    676 		if (debug & D_DHCP)
    677 			logmsg(LOG_DEBUG, "incoming_prefix_stateful: ignoring "
    678 			    "prefix with no valid time\n");
    679 		return;
    680 	}
    681 
    682 	if (debug & D_DHCP)
    683 		logmsg(LOG_DEBUG, "incoming_prefix_stateful(%s, %s/%d)\n",
    684 		    pi->pi_name, inet_ntop(AF_INET6,
    685 		    (void *)&po->nd_opt_pi_prefix, abuf, sizeof (abuf)),
    686 		    po->nd_opt_pi_prefix_len);
    687 	foundpref = _B_FALSE;
    688 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
    689 		if (prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix,
    690 		    po->nd_opt_pi_prefix_len)) {
    691 			if ((pr->pr_flags & IFF_DHCPRUNNING) &&
    692 			    pr->pr_prefix_len != po->nd_opt_pi_prefix_len) {
    693 				pr->pr_prefix_len = po->nd_opt_pi_prefix_len;
    694 				if (pr->pr_flags & IFF_UP) {
    695 					if (debug & D_DHCP)
    696 						logmsg(LOG_DEBUG,
    697 						    "incoming_prefix_stateful:"
    698 						    " set mask on DHCP %s\n",
    699 						    pr->pr_name);
    700 					prefix_update_dhcp(pr);
    701 				}
    702 			}
    703 			if (pr->pr_prefix_len == po->nd_opt_pi_prefix_len &&
    704 			    (!(pr->pr_state & PR_STATIC) ||
    705 			    (pr->pr_flags & IFF_DHCPRUNNING)))
    706 				foundpref = _B_TRUE;
    707 		}
    708 	}
    709 	/*
    710 	 * If there's no matching DHCPv6 prefix present, then create an empty
    711 	 * one so that we'll be able to configure it later.
    712 	 */
    713 	if (!foundpref) {
    714 		pr = prefix_create(pi, po->nd_opt_pi_prefix,
    715 		    po->nd_opt_pi_prefix_len, IFF_DHCPRUNNING);
    716 		if (pr != NULL) {
    717 			pr->pr_state = PR_STATIC;
    718 			if (debug & D_DHCP)
    719 				logmsg(LOG_DEBUG,
    720 				    "incoming_prefix_stateful: created dummy "
    721 				    "prefix for later\n");
    722 		}
    723 	}
    724 }
    725 
    726 /*
    727  * Process prefix options with the autonomous flag set.
    728  * Returns false if this prefix results in a bad address (duplicate)
    729  * This function needs to loop to find the same prefix multiple times
    730  * as if a failover happened earlier, the addresses belonging to
    731  * a different interface may be found here on this interface.
    732  */
    733 static boolean_t
    734 incoming_prefix_addrconf(struct phyint *pi, uchar_t *opt,
    735     struct sockaddr_in6 *from, boolean_t loopback)
    736 {
    737 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
    738 	int plen;
    739 	struct prefix *pr;
    740 	uint32_t validtime, preftime;	/* In seconds */
    741 	char abuf[INET6_ADDRSTRLEN];
    742 	char pbuf[INET6_ADDRSTRLEN];
    743 	boolean_t found_pub = _B_FALSE;
    744 	boolean_t found_tmp = _B_FALSE;
    745 	boolean_t ret;
    746 
    747 	validtime = ntohl(po->nd_opt_pi_valid_time);
    748 	preftime = ntohl(po->nd_opt_pi_preferred_time);
    749 	plen = po->nd_opt_pi_prefix_len;
    750 
    751 	/* Sanity checks */
    752 	if (validtime < preftime) {
    753 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
    754 		    abuf, sizeof (abuf));
    755 		(void) inet_ntop(AF_INET6,
    756 		    (void *)&po->nd_opt_pi_prefix,
    757 		    pbuf, sizeof (pbuf));
    758 		logmsg(LOG_WARNING, "prefix option %s/%u from %s on %s: "
    759 		    "valid %u < pref %u ignored\n",
    760 		    pbuf, plen, abuf, pi->pi_name,
    761 		    validtime, preftime);
    762 		return (_B_FALSE);
    763 	}
    764 
    765 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
    766 		if (pr->pr_prefix_len == plen &&
    767 		    prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) {
    768 
    769 			/* Exclude static prefixes and DHCP */
    770 			if ((pr->pr_state & PR_STATIC) ||
    771 			    (pr->pr_flags & IFF_DHCPRUNNING))
    772 				continue;
    773 			if (pr->pr_flags & IFF_TEMPORARY) {
    774 				/*
    775 				 * If this address is deprecated and its token
    776 				 * doesn't match the current tmp token, we want
    777 				 * to create a new address with the current
    778 				 * token.  So don't count this addr as a match.
    779 				 */
    780 				if (!((pr->pr_flags & IFF_DEPRECATED) &&
    781 				    !token_equal(pi->pi_tmp_token,
    782 				    pr->pr_address, TMP_TOKEN_BITS)))
    783 					found_tmp = _B_TRUE;
    784 			} else {
    785 				found_pub = _B_TRUE;
    786 			}
    787 			(void) incoming_prefix_addrconf_process(pi, pr, opt,
    788 			    from, loopback, _B_FALSE);
    789 		}
    790 	}
    791 
    792 	/*
    793 	 * If we have found a matching prefix (for public and, if temp addrs
    794 	 * are enabled, for temporary) already or validtime is zero, we have
    795 	 * nothing to do.
    796 	 */
    797 	if (validtime == 0 ||
    798 	    (found_pub && (!pi->pi_TmpAddrsEnabled || found_tmp)))
    799 		return (_B_TRUE);
    800 
    801 	if (!found_pub) {
    802 		pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0);
    803 		if (pr == NULL)
    804 			return (_B_TRUE);
    805 		ret = incoming_prefix_addrconf_process(pi, pr, opt, from,
    806 		    loopback, _B_TRUE);
    807 	}
    808 	/*
    809 	 * if processing of the public address failed,
    810 	 * don't bother with the temporary address.
    811 	 */
    812 	if (ret == _B_FALSE)
    813 		return (_B_FALSE);
    814 
    815 	if (pi->pi_TmpAddrsEnabled && !found_tmp) {
    816 		pr = prefix_create(pi, po->nd_opt_pi_prefix, plen,
    817 		    IFF_TEMPORARY);
    818 		if (pr == NULL)
    819 			return (_B_TRUE);
    820 		ret = incoming_prefix_addrconf_process(pi, pr, opt, from,
    821 		    loopback, _B_TRUE);
    822 	}
    823 
    824 	return (ret);
    825 }
    826 
    827 boolean_t
    828 incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr,
    829     uchar_t *opt, struct sockaddr_in6 *from, boolean_t loopback,
    830     boolean_t new_prefix)
    831 {
    832 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
    833 	char abuf[INET6_ADDRSTRLEN];
    834 	char pbuf[INET6_ADDRSTRLEN];
    835 	uint32_t validtime, preftime;	/* In seconds */
    836 	uint32_t recorded_validtime;	/* In seconds */
    837 	int plen;
    838 	struct prefix *other_pr;
    839 
    840 	validtime = ntohl(po->nd_opt_pi_valid_time);
    841 	preftime = ntohl(po->nd_opt_pi_preferred_time);
    842 	plen = po->nd_opt_pi_prefix_len;
    843 	if (!new_prefix) {
    844 		/*
    845 		 * Check 2 hour rule on valid lifetime.
    846 		 * Follows: RFC 2462
    847 		 * If we advertised this prefix ourselves we skip
    848 		 * these checks. They are also skipped if we did not
    849 		 * previously do addrconf on this prefix.
    850 		 */
    851 		recorded_validtime = pr->pr_ValidLifetime / MILLISEC;
    852 
    853 		if (loopback || !(pr->pr_state & PR_AUTO) ||
    854 		    validtime >= MIN_VALID_LIFETIME ||
    855 		    /* LINTED - statement has no consequent */
    856 		    validtime >= recorded_validtime) {
    857 			/* OK */
    858 		} else if (recorded_validtime < MIN_VALID_LIFETIME &&
    859 		    validtime < recorded_validtime) {
    860 			/* Ignore the prefix */
    861 			(void) inet_ntop(AF_INET6,
    862 			    (void *)&from->sin6_addr,
    863 			    abuf, sizeof (abuf));
    864 			(void) inet_ntop(AF_INET6,
    865 			    (void *)&po->nd_opt_pi_prefix,
    866 			    pbuf, sizeof (pbuf));
    867 			logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: "
    868 			    "too short valid lifetime %u stored %u "
    869 			    "- ignored\n",
    870 			    pbuf, plen, abuf, pi->pi_name,
    871 			    validtime, recorded_validtime);
    872 			return (_B_TRUE);
    873 		} else {
    874 			/*
    875 			 * If the router clock runs slower than the
    876 			 * host by 1 second over 2 hours then this
    877 			 * test will set the lifetime back to 2 hours
    878 			 * once i.e. a lifetime decrementing in
    879 			 * realtime might cause the prefix to live an
    880 			 * extra 2 hours on the host.
    881 			 */
    882 			(void) inet_ntop(AF_INET6,
    883 			    (void *)&from->sin6_addr,
    884 			    abuf, sizeof (abuf));
    885 			(void) inet_ntop(AF_INET6,
    886 			    (void *)&po->nd_opt_pi_prefix,
    887 			    pbuf, sizeof (pbuf));
    888 			logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: "
    889 			    "valid time %u stored %u rounded up "
    890 			    "to %u\n",
    891 			    pbuf, plen, abuf, pi->pi_name,
    892 			    validtime, recorded_validtime,
    893 			    MIN_VALID_LIFETIME);
    894 			validtime = MIN_VALID_LIFETIME;
    895 		}
    896 	}
    897 
    898 	/*
    899 	 * For RFC3041 addresses, need to take token lifetime
    900 	 * into account, too.
    901 	 */
    902 	if (pr->pr_flags & IFF_TEMPORARY) {
    903 		uint_t	cur_tpreftime =
    904 		    pi->pi_TmpPreferredLifetime - pi->pi_TmpDesyncFactor;
    905 
    906 		if (new_prefix) {
    907 			validtime = MIN(validtime, pi->pi_TmpValidLifetime);
    908 			preftime = MIN(preftime, cur_tpreftime);
    909 		} else {
    910 			uint_t cur_vexp, cur_pexp, curtime;
    911 			curtime = getcurrenttime() / MILLISEC;
    912 
    913 			cur_vexp = pr->pr_CreateTime + pi->pi_TmpValidLifetime;
    914 			cur_pexp = pr->pr_CreateTime + cur_tpreftime;
    915 			if (curtime > cur_vexp)
    916 				validtime = 0;
    917 			else if ((curtime + validtime) > cur_vexp)
    918 				validtime = cur_vexp - curtime;
    919 			/*
    920 			 * If this is an existing address which was deprecated
    921 			 * because of a bad token, we don't want to update its
    922 			 * preferred lifetime!
    923 			 */
    924 			if ((pr->pr_PreferredLifetime == 0) &&
    925 			    !token_equal(pr->pr_address, pi->pi_tmp_token,
    926 			    TMP_TOKEN_BITS))
    927 				preftime = 0;
    928 			else if (curtime > cur_pexp)
    929 				preftime = 0;
    930 			else if ((curtime + preftime) > cur_pexp)
    931 				preftime = cur_pexp - curtime;
    932 		}
    933 		if ((preftime != 0) && (preftime <= pi->pi_TmpRegenAdvance)) {
    934 			(void) inet_ntop(AF_INET6,
    935 			    (void *)&from->sin6_addr,
    936 			    abuf, sizeof (abuf));
    937 			(void) inet_ntop(AF_INET6,
    938 			    (void *)&po->nd_opt_pi_prefix,
    939 			    pbuf, sizeof (pbuf));
    940 			logmsg(LOG_WARNING, "prefix opt %s/%u from %s on %s: "
    941 			    "preferred lifetime(%d) <= TmpRegenAdvance(%d)\n",
    942 			    pbuf, plen, abuf, pi->pi_name, preftime,
    943 			    pi->pi_TmpRegenAdvance);
    944 			if (new_prefix)
    945 				prefix_delete(pr);
    946 			return (_B_TRUE);
    947 		}
    948 	}
    949 	if (debug & D_TMP)
    950 		logmsg(LOG_DEBUG, "calculated lifetimes(%s, 0x%llx): v %d, "
    951 		    "p %d\n", pr->pr_name, pr->pr_flags, validtime, preftime);
    952 
    953 	if (!(pr->pr_state & PR_AUTO)) {
    954 		int i, tokenlen;
    955 		in6_addr_t *token;
    956 		/*
    957 		 * Form a new local address if the lengths match.
    958 		 */
    959 		if (pr->pr_flags && IFF_TEMPORARY) {
    960 			if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_tmp_token)) {
    961 				if (!tmptoken_create(pi)) {
    962 					prefix_delete(pr);
    963 					return (_