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 2009 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 	bzero(&lifr, sizeof (lifr));
    387 	(void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
    388 
    389 	if (ra->nd_ra_curhoplimit != CURHOP_UNSPECIFIED &&
    390 	    ra->nd_ra_curhoplimit != pi->pi_CurHopLimit) {
    391 		pi->pi_CurHopLimit = ra->nd_ra_curhoplimit;
    392 		lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit;
    393 		set_needed = _B_TRUE;
    394 	}
    395 
    396 	reachable = ntohl(ra->nd_ra_reachable);
    397 	if (reachable != 0 &&
    398 	    reachable != pi->pi_BaseReachableTime) {
    399 		pi->pi_BaseReachableTime = reachable;
    400 		reachable_time_changed = _B_TRUE;
    401 	}
    402 
    403 	if (pi->pi_reach_time_since_random < MIN_REACH_RANDOM_INTERVAL ||
    404 	    reachable_time_changed) {
    405 		phyint_reach_random(pi, _B_FALSE);
    406 		set_needed = _B_TRUE;
    407 	}
    408 	lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime;
    409 
    410 	retrans = ntohl(ra->nd_ra_retransmit);
    411 	if (retrans != 0 &&
    412 	    pi->pi_RetransTimer != retrans) {
    413 		pi->pi_RetransTimer = retrans;
    414 		lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer;
    415 		set_needed = _B_TRUE;
    416 	}
    417 
    418 	if (set_needed) {
    419 		if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) {
    420 			logperror_pi(pi, "incoming_ra: SIOCSLIFLNKINFO");
    421 			return;
    422 		}
    423 	}
    424 
    425 	/*
    426 	 * If the "managed" flag is set, then just assume that the "other" flag
    427 	 * is set as well.  It's not legal to get addresses alone without
    428 	 * getting other data.
    429 	 */
    430 	if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
    431 		ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
    432 
    433 	/*
    434 	 * If either the "managed" or "other" bits have turned on, then it's
    435 	 * now time to invoke DHCP.  If only the "other" bit is set, then don't
    436 	 * get addresses via DHCP; only "other" data.  If "managed" is set,
    437 	 * then we must always get both addresses and "other" data.
    438 	 */
    439 	if (pi->pi_StatefulAddrConf &&
    440 	    (ra->nd_ra_flags_reserved & ~pi->pi_ra_flags &
    441 	    (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))) {
    442 		if (debug & D_DHCP) {
    443 			logmsg(LOG_DEBUG,
    444 			    "incoming_ra: trigger dhcp %s on %s\n",
    445 			    (ra->nd_ra_flags_reserved & ~pi->pi_ra_flags &
    446 			    ND_RA_FLAG_MANAGED) ? "MANAGED" : "OTHER",
    447 			    pi->pi_name);
    448 		}
    449 		pi->pi_ra_flags |= ra->nd_ra_flags_reserved;
    450 		start_dhcp(pi);
    451 	}
    452 
    453 	/* Skip default router code if sent from ourselves */
    454 	if (!loopback) {
    455 		/* Find and update or add default router in list */
    456 		dr = router_lookup(pi, from->sin6_addr);
    457 		router_lifetime = ntohs(ra->nd_ra_router_lifetime);
    458 		if (dr == NULL) {
    459 			if (router_lifetime != 0) {
    460 				dr = router_create(pi, from->sin6_addr,
    461 				    MILLISEC * router_lifetime);
    462 				timer_schedule(dr->dr_lifetime);
    463 			}
    464 		} else {
    465 			dr->dr_lifetime = MILLISEC * router_lifetime;
    466 			if (dr->dr_lifetime != 0)
    467 				timer_schedule(dr->dr_lifetime);
    468 			if ((dr->dr_lifetime != 0 && !dr->dr_inkernel) ||
    469 			    (dr->dr_lifetime == 0 && dr->dr_inkernel))
    470 				router_update_k(dr);
    471 		}
    472 	}
    473 	/* Process any options */
    474 	len -= sizeof (struct nd_router_advert);
    475 	opt = (struct nd_opt_hdr *)&ra[1];
    476 	while (len >= sizeof (struct nd_opt_hdr)) {
    477 		optlen = opt->nd_opt_len * 8;
    478 		switch (opt->nd_opt_type) {
    479 		case ND_OPT_PREFIX_INFORMATION:
    480 			incoming_prefix_opt(pi, (uchar_t *)opt, from,
    481 			    loopback);
    482 			break;
    483 		case ND_OPT_MTU:
    484 			incoming_mtu_opt(pi, (uchar_t *)opt, from);
    485 			break;
    486 		case ND_OPT_SOURCE_LINKADDR:
    487 			/* skip lla option if sent from ourselves! */
    488 			if (!loopback) {
    489 				incoming_lla_opt(pi, (uchar_t *)opt,
    490 				    from, NDF_ISROUTER_ON);
    491 				slla_opt_present = _B_TRUE;
    492 			}
    493 			break;
    494 		default:
    495 			break;
    496 		}
    497 		opt = (struct nd_opt_hdr *)((char *)opt + optlen);
    498 		len -= optlen;
    499 	}
    500 	if (!loopback && !slla_opt_present)
    501 		update_ra_flag(pi, from, NDF_ISROUTER_ON);
    502 	/* Stop sending solicitations */
    503 	check_to_solicit(pi, SOLICIT_DONE);
    504 }
    505 
    506 /*
    507  * Process a received prefix option.
    508  * Unless addrconf is turned off we process both the addrconf and the
    509  * onlink aspects of the prefix option.
    510  *
    511  * Note that when a flag (onlink or auto) is turned off we do nothing -
    512  * the prefix will time out.
    513  */
    514 static void
    515 incoming_prefix_opt(struct phyint *pi, uchar_t *opt,
    516     struct sockaddr_in6 *from, boolean_t loopback)
    517 {
    518 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
    519 	boolean_t	good_prefix = _B_TRUE;
    520 
    521 	if (8 * po->nd_opt_pi_len != sizeof (*po)) {
    522 		char abuf[INET6_ADDRSTRLEN];
    523 
    524 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
    525 		    abuf, sizeof (abuf));
    526 		logmsg(LOG_INFO, "prefix option from %s on %s wrong size "
    527 		    "(%d bytes)\n",
    528 		    abuf, pi->pi_name,
    529 		    8 * (int)po->nd_opt_pi_len);
    530 		return;
    531 	}
    532 	if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) {
    533 		char abuf[INET6_ADDRSTRLEN];
    534 
    535 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
    536 		    abuf, sizeof (abuf));
    537 		logmsg(LOG_INFO, "RA from %s on %s contains link-local prefix "
    538 		    "- ignored\n",
    539 		    abuf, pi->pi_name);
    540 		return;
    541 	}
    542 	if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) &&
    543 	    pi->pi_StatelessAddrConf) {
    544 		good_prefix = incoming_prefix_addrconf(pi, opt, from, loopback);
    545 	}
    546 	if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) &&
    547 	    good_prefix) {
    548 		incoming_prefix_onlink(pi, opt);
    549 	}
    550 	if (pi->pi_StatefulAddrConf)
    551 		incoming_prefix_stateful(pi, opt);
    552 }
    553 
    554 /*
    555  * Process prefix options with the onlink flag set.
    556  *
    557  * If there are no routers ndpd will add an onlink
    558  * default route which will allow communication
    559  * between neighbors.
    560  *
    561  * This function needs to loop to find the same prefix multiple times
    562  * as if a failover happened earlier, the addresses belonging to
    563  * a different interface may be found here on this interface.
    564  */
    565 static void
    566 incoming_prefix_onlink(struct phyint *pi, uchar_t *opt)
    567 {
    568 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
    569 	int plen;
    570 	struct prefix *pr;
    571 	uint32_t validtime;	/* Without 2 hour rule */
    572 	boolean_t found_one = _B_FALSE;
    573 
    574 	plen = po->nd_opt_pi_prefix_len;
    575 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
    576 		if (pr->pr_prefix_len == plen &&
    577 		    prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) {
    578 			/* Exclude static prefixes */
    579 			if (pr->pr_state & PR_STATIC)
    580 				continue;
    581 			found_one = _B_TRUE;
    582 			incoming_prefix_onlink_process(pr, opt);
    583 		}
    584 	}
    585 
    586 	validtime = ntohl(po->nd_opt_pi_valid_time);
    587 	/*
    588 	 * If we have found a matching prefix already or validtime
    589 	 * is zero, we have nothing to do.
    590 	 */
    591 	if (validtime == 0 || found_one)
    592 		return;
    593 	pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0);
    594 	if (pr == NULL)
    595 		return;
    596 	incoming_prefix_onlink_process(pr, opt);
    597 }
    598 
    599 void
    600 incoming_prefix_onlink_process(struct prefix *pr, uchar_t *opt)
    601 {
    602 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
    603 	uint32_t validtime;	/* Without 2 hour rule */
    604 	char abuf[INET6_ADDRSTRLEN];
    605 
    606 	validtime = ntohl(po->nd_opt_pi_valid_time);
    607 	if (validtime != 0)
    608 		pr->pr_state |= PR_ONLINK;
    609 	else
    610 		pr->pr_state &= ~PR_ONLINK;
    611 
    612 	/*
    613 	 * Convert from seconds to milliseconds avoiding overflow.
    614 	 * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1
    615 	 * (4 billion seconds - about 130 years) we will in fact time
    616 	 * out the prefix after 4 billion milliseconds - 46 days).
    617 	 * Thus the longest lifetime (apart from infinity) is 46 days.
    618 	 * Note that this ensures that PREFIX_INFINITY still means "forever".
    619 	 */
    620 	if (pr->pr_flags & IFF_TEMPORARY) {
    621 		pr->pr_OnLinkLifetime = pr->pr_ValidLifetime;
    622 	} else {
    623 		if (validtime >= PREFIX_INFINITY / MILLISEC)
    624 			pr->pr_OnLinkLifetime = PREFIX_INFINITY - 1;
    625 		else
    626 			pr->pr_OnLinkLifetime = validtime * MILLISEC;
    627 	}
    628 	pr->pr_OnLinkFlag = _B_TRUE;
    629 	if (debug & (D_PREFIX|D_TMP)) {
    630 		logmsg(LOG_DEBUG, "incoming_prefix_onlink_process(%s, %s/%u) "
    631 		    "onlink %u state 0x%x, kstate 0x%x\n",
    632 		    pr->pr_name, inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
    633 		    abuf, sizeof (abuf)), pr->pr_prefix_len,
    634 		    pr->pr_OnLinkLifetime, pr->pr_state, pr->pr_kernel_state);
    635 	}
    636 
    637 	if (pr->pr_kernel_state != pr->pr_state) {
    638 		prefix_update_k(pr);
    639 	}
    640 
    641 	if (pr->pr_OnLinkLifetime != 0)
    642 		timer_schedule(pr->pr_OnLinkLifetime);
    643 }
    644 
    645 /*
    646  * Process all prefix options by locating the DHCPv6-configured interfaces, and
    647  * applying the netmasks as needed.
    648  */
    649 static void
    650 incoming_prefix_stateful(struct phyint *pi, uchar_t *opt)
    651 {
    652 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
    653 	struct prefix *pr;
    654 	boolean_t foundpref;
    655 	char abuf[INET6_ADDRSTRLEN];
    656 
    657 	/* Make sure it's a valid prefix. */
    658 	if (ntohl(po->nd_opt_pi_valid_time) == 0) {
    659 		if (debug & D_DHCP)
    660 			logmsg(LOG_DEBUG, "incoming_prefix_stateful: ignoring "
    661 			    "prefix with no valid time\n");
    662 		return;
    663 	}
    664 
    665 	if (debug & D_DHCP)
    666 		logmsg(LOG_DEBUG, "incoming_prefix_stateful(%s, %s/%d)\n",
    667 		    pi->pi_name, inet_ntop(AF_INET6,
    668 		    (void *)&po->nd_opt_pi_prefix, abuf, sizeof (abuf)),
    669 		    po->nd_opt_pi_prefix_len);
    670 	foundpref = _B_FALSE;
    671 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
    672 		if (prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix,
    673 		    po->nd_opt_pi_prefix_len)) {
    674 			if ((pr->pr_flags & IFF_DHCPRUNNING) &&
    675 			    pr->pr_prefix_len != po->nd_opt_pi_prefix_len) {
    676 				pr->pr_prefix_len = po->nd_opt_pi_prefix_len;
    677 				if (pr->pr_flags & IFF_UP) {
    678 					if (debug & D_DHCP)
    679 						logmsg(LOG_DEBUG,
    680 						    "incoming_prefix_stateful:"
    681 						    " set mask on DHCP %s\n",
    682 						    pr->pr_name);
    683 					prefix_update_dhcp(pr);
    684 				}
    685 			}
    686 			if (pr->pr_prefix_len == po->nd_opt_pi_prefix_len &&
    687 			    (!(pr->pr_state & PR_STATIC) ||
    688 			    (pr->pr_flags & IFF_DHCPRUNNING)))
    689 				foundpref = _B_TRUE;
    690 		}
    691 	}
    692 	/*
    693 	 * If there's no matching DHCPv6 prefix present, then create an empty
    694 	 * one so that we'll be able to configure it later.
    695 	 */
    696 	if (!foundpref) {
    697 		pr = prefix_create(pi, po->nd_opt_pi_prefix,
    698 		    po->nd_opt_pi_prefix_len, IFF_DHCPRUNNING);
    699 		if (pr != NULL) {
    700 			pr->pr_state = PR_STATIC;
    701 			if (debug & D_DHCP)
    702 				logmsg(LOG_DEBUG,
    703 				    "incoming_prefix_stateful: created dummy "
    704 				    "prefix for later\n");
    705 		}
    706 	}
    707 }
    708 
    709 /*
    710  * Process prefix options with the autonomous flag set.
    711  * Returns false if this prefix results in a bad address (duplicate)
    712  * This function needs to loop to find the same prefix multiple times
    713  * as if a failover happened earlier, the addresses belonging to
    714  * a different interface may be found here on this interface.
    715  */
    716 static boolean_t
    717 incoming_prefix_addrconf(struct phyint *pi, uchar_t *opt,
    718     struct sockaddr_in6 *from, boolean_t loopback)
    719 {
    720 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
    721 	int plen;
    722 	struct prefix *pr;
    723 	uint32_t validtime, preftime;	/* In seconds */
    724 	char abuf[INET6_ADDRSTRLEN];
    725 	char pbuf[INET6_ADDRSTRLEN];
    726 	boolean_t found_pub = _B_FALSE;
    727 	boolean_t found_tmp = _B_FALSE;
    728 	boolean_t ret;
    729 
    730 	validtime = ntohl(po->nd_opt_pi_valid_time);
    731 	preftime = ntohl(po->nd_opt_pi_preferred_time);
    732 	plen = po->nd_opt_pi_prefix_len;
    733 
    734 	/* Sanity checks */
    735 	if (validtime < preftime) {
    736 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
    737 		    abuf, sizeof (abuf));
    738 		(void) inet_ntop(AF_INET6,
    739 		    (void *)&po->nd_opt_pi_prefix,
    740 		    pbuf, sizeof (pbuf));
    741 		logmsg(LOG_WARNING, "prefix option %s/%u from %s on %s: "
    742 		    "valid %u < pref %u ignored\n",
    743 		    pbuf, plen, abuf, pi->pi_name,
    744 		    validtime, preftime);
    745 		return (_B_FALSE);
    746 	}
    747 
    748 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
    749 		if (pr->pr_prefix_len == plen &&
    750 		    prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) {
    751 
    752 			/* Exclude static prefixes and DHCP */
    753 			if ((pr->pr_state & PR_STATIC) ||
    754 			    (pr->pr_flags & IFF_DHCPRUNNING))
    755 				continue;
    756 			if (pr->pr_flags & IFF_TEMPORARY) {
    757 				/*
    758 				 * If this address is deprecated and its token
    759 				 * doesn't match the current tmp token, we want
    760 				 * to create a new address with the current
    761 				 * token.  So don't count this addr as a match.
    762 				 */
    763 				if (!((pr->pr_flags & IFF_DEPRECATED) &&
    764 				    !token_equal(pi->pi_tmp_token,
    765 				    pr->pr_address, TMP_TOKEN_BITS)))
    766 					found_tmp = _B_TRUE;
    767 			} else {
    768 				found_pub = _B_TRUE;
    769 			}
    770 			(void) incoming_prefix_addrconf_process(pi, pr, opt,
    771 			    from, loopback, _B_FALSE);
    772 		}
    773 	}
    774 
    775 	/*
    776 	 * If we have found a matching prefix (for public and, if temp addrs
    777 	 * are enabled, for temporary) already or validtime is zero, we have
    778 	 * nothing to do.
    779 	 */
    780 	if (validtime == 0 ||
    781 	    (found_pub && (!pi->pi_TmpAddrsEnabled || found_tmp)))
    782 		return (_B_TRUE);
    783 
    784 	if (!found_pub) {
    785 		pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0);
    786 		if (pr == NULL)
    787 			return (_B_TRUE);
    788 		ret = incoming_prefix_addrconf_process(pi, pr, opt, from,
    789 		    loopback, _B_TRUE);
    790 	}
    791 	/*
    792 	 * if processing of the public address failed,
    793 	 * don't bother with the temporary address.
    794 	 */
    795 	if (ret == _B_FALSE)
    796 		return (_B_FALSE);
    797 
    798 	if (pi->pi_TmpAddrsEnabled && !found_tmp) {
    799 		pr = prefix_create(pi, po->nd_opt_pi_prefix, plen,
    800 		    IFF_TEMPORARY);
    801 		if (pr == NULL)
    802 			return (_B_TRUE);
    803 		ret = incoming_prefix_addrconf_process(pi, pr, opt, from,
    804 		    loopback, _B_TRUE);
    805 	}
    806 
    807 	return (ret);
    808 }
    809 
    810 boolean_t
    811 incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr,
    812     uchar_t *opt, struct sockaddr_in6 *from, boolean_t loopback,
    813     boolean_t new_prefix)
    814 {
    815 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
    816 	char abuf[INET6_ADDRSTRLEN];
    817 	char pbuf[INET6_ADDRSTRLEN];
    818 	uint32_t validtime, preftime;	/* In seconds */
    819 	uint32_t recorded_validtime;	/* In seconds */
    820 	int plen;
    821 	struct prefix *other_pr;
    822 
    823 	validtime = ntohl(po->nd_opt_pi_valid_time);
    824 	preftime = ntohl(po->nd_opt_pi_preferred_time);
    825 	plen = po->nd_opt_pi_prefix_len;
    826 	if (!new_prefix) {
    827 		/*
    828 		 * Check 2 hour rule on valid lifetime.
    829 		 * Follows: RFC 2462
    830 		 * If we advertised this prefix ourselves we skip
    831 		 * these checks. They are also skipped if we did not
    832 		 * previously do addrconf on this prefix.
    833 		 */
    834 		recorded_validtime = pr->pr_ValidLifetime / MILLISEC;
    835 
    836 		if (loopback || !(pr->pr_state & PR_AUTO) ||
    837 		    validtime >= MIN_VALID_LIFETIME ||
    838 		    /* LINTED - statement has no consequent */
    839 		    validtime >= recorded_validtime) {
    840 			/* OK */
    841 		} else if (recorded_validtime < MIN_VALID_LIFETIME &&
    842 		    validtime < recorded_validtime) {
    843 			/* Ignore the prefix */
    844 			(void) inet_ntop(AF_INET6,
    845 			    (void *)&from->sin6_addr,
    846 			    abuf, sizeof (abuf));
    847 			(void) inet_ntop(AF_INET6,
    848 			    (void *)&po->nd_opt_pi_prefix,
    849 			    pbuf, sizeof (pbuf));
    850 			logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: "
    851 			    "too short valid lifetime %u stored %u "
    852 			    "- ignored\n",
    853 			    pbuf, plen, abuf, pi->pi_name,
    854 			    validtime, recorded_validtime);
    855 			return (_B_TRUE);
    856 		} else {
    857 			/*
    858 			 * If the router clock runs slower than the
    859 			 * host by 1 second over 2 hours then this
    860 			 * test will set the lifetime back to 2 hours
    861 			 * once i.e. a lifetime decrementing in
    862 			 * realtime might cause the prefix to live an
    863 			 * extra 2 hours on the host.
    864 			 */
    865 			(void) inet_ntop(AF_INET6,
    866 			    (void *)&from->sin6_addr,
    867 			    abuf, sizeof (abuf));
    868 			(void) inet_ntop(AF_INET6,
    869 			    (void *)&po->nd_opt_pi_prefix,
    870 			    pbuf, sizeof (pbuf));
    871 			logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: "
    872 			    "valid time %u stored %u rounded up "
    873 			    "to %u\n",
    874 			    pbuf, plen, abuf, pi->pi_name,
    875 			    validtime, recorded_validtime,
    876 			    MIN_VALID_LIFETIME);
    877 			validtime = MIN_VALID_LIFETIME;
    878 		}
    879 	}
    880 
    881 	/*
    882 	 * For RFC3041 addresses, need to take token lifetime
    883 	 * into account, too.
    884 	 */
    885 	if (pr->pr_flags & IFF_TEMPORARY) {
    886 		uint_t	cur_tpreftime =
    887 		    pi->pi_TmpPreferredLifetime - pi->pi_TmpDesyncFactor;
    888 
    889 		if (new_prefix) {
    890 			validtime = MIN(validtime, pi->pi_TmpValidLifetime);
    891 			preftime = MIN(preftime, cur_tpreftime);
    892 		} else {
    893 			uint_t cur_vexp, cur_pexp, curtime;
    894 			curtime = getcurrenttime() / MILLISEC;
    895 
    896 			cur_vexp = pr->pr_CreateTime + pi->pi_TmpValidLifetime;
    897 			cur_pexp = pr->pr_CreateTime + cur_tpreftime;
    898 			if (curtime > cur_vexp)
    899 				validtime = 0;
    900 			else if ((curtime + validtime) > cur_vexp)
    901 				validtime = cur_vexp - curtime;
    902 			/*
    903 			 * If this is an existing address which was deprecated
    904 			 * because of a bad token, we don't want to update its
    905 			 * preferred lifetime!
    906 			 */
    907 			if ((pr->pr_PreferredLifetime == 0) &&
    908 			    !token_equal(pr->pr_address, pi->pi_tmp_token,
    909 			    TMP_TOKEN_BITS))
    910 				preftime = 0;
    911 			else if (curtime > cur_pexp)
    912 				preftime = 0;
    913 			else if ((curtime + preftime) > cur_pexp)
    914 				preftime = cur_pexp - curtime;
    915 		}
    916 		if ((preftime != 0) && (preftime <= pi->pi_TmpRegenAdvance)) {
    917 			(void) inet_ntop(AF_INET6,
    918 			    (void *)&from->sin6_addr,
    919 			    abuf, sizeof (abuf));
    920 			(void) inet_ntop(AF_INET6,
    921 			    (void *)&po->nd_opt_pi_prefix,
    922 			    pbuf, sizeof (pbuf));
    923 			logmsg(LOG_WARNING, "prefix opt %s/%u from %s on %s: "
    924 			    "preferred lifetime(%d) <= TmpRegenAdvance(%d)\n",
    925 			    pbuf, plen, abuf, pi->pi_name, preftime,
    926 			    pi->pi_TmpRegenAdvance);
    927 			if (new_prefix)
    928 				prefix_delete(pr);
    929 			return (_B_TRUE);
    930 		}
    931 	}
    932 	if (debug & D_TMP)
    933 		logmsg(LOG_DEBUG, "calculated lifetimes(%s, 0x%llx): v %d, "
    934 		    "p %d\n", pr->pr_name, pr->pr_flags, validtime, preftime);
    935 
    936 	if (!(pr->pr_state & PR_AUTO)) {
    937 		int i, tokenlen;
    938 		in6_addr_t *token;
    939 		/*
    940 		 * Form a new local address if the lengths match.
    941 		 */
    942 		if (pr->pr_flags && IFF_TEMPORARY) {
    943 			if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_tmp_token)) {
    944 				if (!tmptoken_create(pi)) {
    945 					prefix_delete(pr);
    946 					return (_B_TRUE);
    947 				}
    948 			}
    949 			tokenlen = TMP_TOKEN_BITS;
    950 			token = &pi->pi_tmp_token;
    951 		} else {
    952 			tokenlen = pi->pi_token_length;
    953 			token = &pi->pi_token;
    954 		}
    955 		if (pr->pr_prefix_len + tokenlen != IPV6_ABITS) {
    956 			(void) inet_ntop(AF_INET6,
    957 			    (void *)&from->sin6_addr,
    958 			    abuf, sizeof (abuf));
    959 			(void) inet_ntop(AF_INET6,
    960 			    (void *)&po->nd_opt_pi_prefix,
    961 			    pbuf, sizeof (pbuf));
    962 			logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: "
    963 			    "mismatched length %d token length %d\n",
    964 			    pbuf, plen, abuf, pi->pi_name,
    965 			    pr->pr_prefix_len, tokenlen);
    966 			return (_B_TRUE);
    967 		}
    968 		for (i = 0; i < 16; i++) {
    969 			/*
    970 			 * prefix_create ensures that pr_prefix has all-zero
    971 			 * bits after prefixlen.
    972 			 */
    973 			pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] |
    974 			    token->s6_addr[i];
    975 		}
    976 		/*
    977 		 * Check if any other physical interface has the same
    978 		 * address configured already
    979 		 */
    980 		if ((other_pr = prefix_lookup_addr_match(pr)) != NULL) {
    981 			/*
    982 			 * Delete this prefix structure as kernel
    983 			 * does not allow duplicated addresses
    984 			 */
    985 			logmsg(LOG_ERR, "incoming_prefix_addrconf_process: "
    986 			    "Duplicate prefix %s received on interface %s\n",
    987 			    inet_ntop(AF_INET6, &po->nd_opt_pi_prefix, abuf,
    988 			    sizeof (abuf)), pi->pi_name);
    989 			logmsg(LOG_ERR, "incoming_prefix_addrconf_process: "
    990 			    "Prefix already exists in interface %s\n",
    991 			    other_pr->pr_physical->pi_name);
    992 			if (new_prefix) {
    993 				prefix_delete(pr);
    994 				return (_B_FALSE);
    995 			}
    996 			/* Ignore for addrconf purposes */
    997 			validtime = preftime = 0;
    998 		}
    999 		if ((pr->pr_flags & IFF_TEMPORARY) && new_prefix) {
   1000 			pr->pr_CreateTime = getcurrenttime() / MILLISEC;
   1001 			if (debug & D_TMP)
   1002 				logmsg(LOG_DEBUG,
   1003 				    "created tmp addr(%s v %d p %d)\n",
   1004 				    pr->pr_name, validtime, preftime);
   1005 		}
   1006 	}
   1007 
   1008 	if (validtime != 0)
   1009 		pr->pr_state |= PR_AUTO;
   1010 	else
   1011 		pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED);
   1012 	if (preftime != 0 || !(pr->pr_state & PR_AUTO))
   1013 		pr->pr_state &= ~PR_DEPRECATED;
   1014 	else
   1015 		pr->pr_state |= PR_DEPRECATED;
   1016 
   1017 	/*
   1018 	 * Convert from seconds to milliseconds avoiding overflow.
   1019 	 * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1
   1020 	 * (4 billion seconds - about 130 years) we will in fact time
   1021 	 * out the prefix after 4 billion milliseconds - 46 days).
   1022 	 * Thus the longest lifetime (apart from infinity) is 46 days.
   1023 	 * Note that this ensures that PREFIX_INFINITY still means "forever".
   1024 	 */
   1025 	if (validtime >= PREFIX_INFINITY / MILLISEC)
   1026 		pr->pr_ValidLifetime = PREFIX_INFINITY - 1;
   1027 	else
   1028 		pr->pr_ValidLifetime = validtime * MILLISEC;
   1029 	if (preftime >= PREFIX_INFINITY / MILLISEC)
   1030 		pr->pr_PreferredLifetime = PREFIX_INFINITY - 1;
   1031 	else
   1032 		pr->pr_PreferredLifetime = preftime * MILLISEC;
   1033 	pr->pr_AutonomousFlag = _B_TRUE;
   1034 
   1035 	if (debug & D_PREFIX) {
   1036 		logmsg(LOG_DEBUG, "incoming_prefix_addrconf_process(%s, %s/%u) "
   1037 		    "valid %u pref %u\n",
   1038 		    pr->pr_physical->pi_name,
   1039 		    inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
   1040 		    abuf, sizeof (abuf)), pr->pr_prefix_len,
   1041 		    pr->pr_ValidLifetime, pr->pr_PreferredLifetime);
   1042 	}
   1043 
   1044 	if (pr->pr_state & PR_AUTO) {
   1045 		/* Take the min of the two timeouts by calling it twice */
   1046 		if (pr->pr_ValidLifetime != 0)
   1047 			timer_schedule(pr->pr_ValidLifetime);
   1048 		if (pr->pr_PreferredLifetime != 0)
   1049 			timer_schedule(pr->pr_PreferredLifetime);
   1050 	}
   1051 	if (pr->pr_kernel_state != pr->pr_state) {
   1052 		/* Log a message when an addrconf prefix goes away */
   1053 		if ((pr->pr_kernel_state & PR_AUTO) &&
   1054 		    !(pr->pr_state & PR_AUTO)) {
   1055 			char abuf[INET6_ADDRSTRLEN];
   1056 
   1057 			logmsg(LOG_WARNING, "Address removed due to zero "
   1058 			    "valid lifetime %s\n",
   1059 			    inet_ntop(AF_INET6, (void *)&pr->pr_address,
   1060 			    abuf, sizeof (abuf)));
   1061 		}
   1062 		prefix_update_k(pr);
   1063 	}
   1064 	return (_B_TRUE);
   1065 }
   1066 
   1067 /*
   1068  * Process an MTU option received in a router advertisement.
   1069  */
   1070 static void
   1071 incoming_mtu_opt(struct phyint *pi, uchar_t *opt,
   1072     struct sockaddr_in6 *from)
   1073 {
   1074 	struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt;
   1075 	struct lifreq lifr;
   1076 	uint32_t mtu;
   1077 
   1078 	if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) {
   1079 		char abuf[INET6_ADDRSTRLEN];
   1080 
   1081 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
   1082 		    abuf, sizeof (abuf));
   1083 		logmsg(LOG_INFO, "mtu option from %s on %s wrong size "
   1084 		    "(%d bytes)\n",
   1085 		    abuf, pi->pi_name,
   1086 		    8 * (int)mo->nd_opt_mtu_len);
   1087 		return;
   1088 	}
   1089 	mtu = ntohl(mo->nd_opt_mtu_mtu);
   1090 	if (pi->pi_LinkMTU == mtu)
   1091 		return;	/* No change */
   1092 	if (mtu > pi->pi_mtu) {
   1093 		/* Can't exceed physical MTU */
   1094 		char abuf[INET6_ADDRSTRLEN];
   1095 
   1096 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
   1097 		    abuf, sizeof (abuf));
   1098 		logmsg(LOG_INFO, "mtu option from %s on %s too large "
   1099 		    "MTU %d - %d\n", abuf, pi->pi_name, mtu, pi->pi_mtu);
   1100 		return;
   1101 	}
   1102 	if (mtu < IPV6_MIN_MTU) {
   1103 		char abuf[INET6_ADDRSTRLEN];
   1104 
   1105 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
   1106 		    abuf, sizeof (abuf));
   1107 		logmsg(LOG_INFO, "mtu option from %s on %s too small "
   1108 		    "MTU (%d)\n", abuf, pi->pi_name, mtu);
   1109 		return;
   1110 	}
   1111 
   1112 	pi->pi_LinkMTU = mtu;
   1113 	bzero(&lifr, sizeof (lifr));
   1114 	(void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
   1115 	lifr.lifr_ifinfo.lir_maxmtu = pi->pi_LinkMTU;
   1116 	if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) {
   1117 		logperror_pi(pi, "incoming_mtu_opt: SIOCSLIFLNKINFO");
   1118 		return;
   1119 	}
   1120 }
   1121 
   1122 /*
   1123  * Process a source link-layer address option received in a router
   1124  * advertisement or solicitation.
   1125  */
   1126 static void
   1127 incoming_lla_opt(struct phyint *pi, uchar_t *opt,
   1128     struct sockaddr_in6 *from, int isrouter)
   1129 {
   1130 	struct nd_opt_lla *lo = (struct nd_opt_lla *)opt;
   1131 	struct lifreq lifr;
   1132 	struct sockaddr_in6 *sin6;
   1133 	int max_content_len;
   1134 
   1135 	/*
   1136 	 * Get our link-layer address length.  We may not have one, in which
   1137 	 * case we can just bail.
   1138 	 */
   1139 	if (phyint_get_lla(pi, &lifr) != 0)
   1140 		return;
   1141 
   1142 	/*
   1143 	 * Can't remove padding since it is link type specific.
   1144 	 * However, we check against the length of our link-layer address.
   1145 	 * Note: assumes that all links have a fixed length address.
   1146 	 */
   1147 	max_content_len = lo->nd_opt_lla_len * 8 - sizeof (struct nd_opt_hdr);
   1148 	if (max_content_len < lifr.lifr_nd.lnr_hdw_len ||
   1149 	    (max_content_len >= 8 &&
   1150 	    max_content_len - 7 > lifr.lifr_nd.lnr_hdw_len)) {
   1151 		char abuf[INET6_ADDRSTRLEN];
   1152 
   1153 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
   1154 		    abuf, sizeof (abuf));
   1155 		logmsg(LOG_INFO, "lla option from %s on %s too long with bad "
   1156 		    "physaddr length (%d vs. %d bytes)\n", abuf, pi->pi_name,
   1157 		    max_content_len, lifr.lifr_nd.lnr_hdw_len);
   1158 		return;
   1159 	}
   1160 
   1161 	bcopy(lo->nd_opt_lla_hdw_addr, lifr.lifr_nd.lnr_hdw_addr,
   1162 	    lifr.lifr_nd.lnr_hdw_len);
   1163 
   1164 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr;
   1165 	bzero(sin6, sizeof (struct sockaddr_in6));
   1166 	sin6->sin6_family = AF_INET6;
   1167 	sin6->sin6_addr = from->sin6_addr;
   1168 
   1169 	/*
   1170 	 * Set IsRouter flag if RA; clear if RS.
   1171 	 */
   1172 	lifr.lifr_nd.lnr_state_create = ND_STALE;
   1173 	lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED;
   1174 	lifr.lifr_nd.lnr_state_diff_lla = ND_STALE;
   1175 	lifr.lifr_nd.lnr_flags = isrouter;
   1176 	(void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
   1177 	if (ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr) < 0) {
   1178 		logperror_pi(pi, "incoming_lla_opt: SIOCLIFSETND");
   1179 		return;
   1180 	}
   1181 }
   1182 
   1183 /*
   1184  * Verify the content of the received router advertisement against our
   1185  * own configuration as specified in RFC 2461.
   1186  */
   1187 static void
   1188 verify_ra_consistency(struct phyint *pi, struct nd_router_advert *ra, int len,
   1189     struct sockaddr_in6 *from)
   1190 {
   1191 	char frombuf[INET6_ADDRSTRLEN];
   1192 	struct nd_opt_hdr *opt;
   1193 	int optlen;
   1194 	uint_t reachable, retrans;
   1195 	boolean_t pktflag, myflag;
   1196 
   1197 	(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
   1198 	    frombuf, sizeof (frombuf));
   1199 
   1200 	if (ra->nd_ra_curhoplimit != 0 &&
   1201 	    pi->pi_AdvCurHopLimit != 0 &&
   1202 	    ra->nd_ra_curhoplimit != pi->pi_AdvCurHopLimit) {
   1203 		logmsg(LOG_INFO, "RA from %s on %s inconsistent cur hop "
   1204 		    "limit:\n\treceived %d configuration %d\n",
   1205 		    frombuf, pi->pi_name,
   1206 		    ra->nd_ra_curhoplimit, pi->pi_AdvCurHopLimit);
   1207 	}
   1208 
   1209 	reachable = ntohl(ra->nd_ra_reachable);
   1210 	if (reachable != 0 && pi->pi_AdvReachableTime != 0 &&
   1211 	    reachable != pi->pi_AdvReachableTime) {
   1212 		logmsg(LOG_INFO, "RA from %s on %s inconsistent reachable "
   1213 		    "time:\n\treceived %d configuration %d\n",
   1214 		    frombuf, pi->pi_name,
   1215 		    reachable, pi->pi_AdvReachableTime);
   1216 	}
   1217 
   1218 	retrans = ntohl(ra->nd_ra_retransmit);
   1219 	if (retrans != 0 && pi->pi_AdvRetransTimer != 0 &&
   1220 	    retrans != pi->pi_AdvRetransTimer) {
   1221 		logmsg(LOG_INFO, "RA from %s on %s inconsistent retransmit "
   1222 		    "timer:\n\treceived %d configuration %d\n",
   1223 		    frombuf, pi->pi_name,
   1224 		    retrans, pi->pi_AdvRetransTimer);
   1225 	}
   1226 
   1227 	pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != 0);
   1228 	myflag = (pi->pi_AdvManagedFlag != 0);
   1229 	if (pktflag != myflag) {
   1230 		logmsg(LOG_INFO, "RA from %s on %s inconsistent managed "
   1231 		    "flag:\n\treceived %s configuration %s\n",
   1232 		    frombuf, pi->pi_name,
   1233 		    (pktflag ? "ON" : "OFF"),
   1234 		    (myflag ? "ON" : "OFF"));
   1235 	}
   1236 	pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != 0);
   1237 	myflag = (pi->pi_AdvOtherConfigFlag != 0);
   1238 	if (pktflag != myflag) {
   1239 		logmsg(LOG_INFO, "RA from %s on %s inconsistent other config "
   1240 		    "flag:\n\treceived %s configuration %s\n",
   1241 		    frombuf, pi->pi_name,
   1242 		    (pktflag ? "ON" : "OFF"),
   1243 		    (myflag ? "ON" : "OFF"));
   1244 	}
   1245 
   1246 	/* Process any options */
   1247 	len -= sizeof (struct nd_router_advert);
   1248 	opt = (struct nd_opt_hdr *)&ra[1];
   1249 	while (len >= sizeof (struct nd_opt_hdr)) {
   1250 		optlen = opt->nd_opt_len * 8;
   1251 		switch (opt->nd_opt_type) {
   1252 		case ND_OPT_PREFIX_INFORMATION:
   1253 			verify_prefix_opt(pi, (uchar_t *)opt, frombuf);
   1254 			break;
   1255 		case ND_OPT_MTU:
   1256 			verify_mtu_opt(pi, (uchar_t *)opt, frombuf);
   1257 			break;
   1258 		default:
   1259 			break;
   1260 		}
   1261 		opt = (struct nd_opt_hdr *)((char *)opt + optlen);
   1262 		len -= optlen;
   1263 	}
   1264 }
   1265 
   1266 /*
   1267  * Verify that the lifetimes and onlink/auto flags are consistent
   1268  * with our settings.
   1269  */
   1270 static void
   1271 verify_prefix_opt(struct phyint *pi, uchar_t *opt, char *frombuf)
   1272 {
   1273 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
   1274 	int plen;
   1275 	struct adv_prefix *adv_pr;
   1276 	uint32_t validtime, preftime;
   1277 	char prefixbuf[INET6_ADDRSTRLEN];
   1278 	int pktflag, myflag;
   1279 
   1280 	if (8 * po->nd_opt_pi_len != sizeof (*po)) {
   1281 		logmsg(LOG_INFO, "RA prefix option from %s on %s wrong size "
   1282 		    "(%d bytes)\n",
   1283 		    frombuf, pi->pi_name,
   1284 		    8 * (int)po->nd_opt_pi_len);
   1285 		return;
   1286 	}
   1287 	if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) {
   1288 		logmsg(LOG_INFO, "RA from %s on %s contains link-local "
   1289 		    "prefix - ignored\n",
   1290 		    frombuf, pi->pi_name);
   1291 		return;
   1292 	}
   1293 	plen = po->nd_opt_pi_prefix_len;
   1294 	adv_pr = adv_prefix_lookup(pi, po->nd_opt_pi_prefix, plen);
   1295 	if (adv_pr == NULL)
   1296 		return;
   1297 
   1298 	/* Ignore prefixes which we do not advertise */
   1299 	if (!adv_pr->adv_pr_AdvAutonomousFlag && !adv_pr->adv_pr_AdvOnLinkFlag)
   1300 		return;
   1301 	(void) inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix,
   1302 	    prefixbuf, sizeof (prefixbuf));
   1303 	pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) != 0);
   1304 	myflag = (adv_pr->adv_pr_AdvAutonomousFlag != 0);
   1305 	if (pktflag != myflag) {
   1306 		logmsg(LOG_INFO,
   1307 		    "RA from %s on %s inconsistent autonomous flag for \n\t"
   1308 		    "prefix %s/%u: received %s configuration %s\n",
   1309 		    frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len,
   1310 		    (pktflag ? "ON" : "OFF"),
   1311 		    (myflag ? "ON" : "OFF"));
   1312 	}
   1313 
   1314 	pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) != 0);
   1315 	myflag = (adv_pr->adv_pr_AdvOnLinkFlag != 0);
   1316 	if (pktflag != myflag) {
   1317 		logmsg(LOG_INFO, "RA from %s on %s inconsistent on link flag "
   1318 		    "for \n\tprefix %s/%u: received %s configuration %s\n",
   1319 		    frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len,
   1320 		    (pktflag ? "ON" : "OFF"),
   1321 		    (myflag ? "ON" : "OFF"));
   1322 	}
   1323 	validtime = ntohl(po->nd_opt_pi_valid_time);
   1324 	preftime = ntohl(po->nd_opt_pi_preferred_time);
   1325 
   1326 	/*
   1327 	 * Take into account variation for lifetimes decrementing
   1328 	 * in real time. Allow +/- 10 percent and +/- 10 seconds.
   1329 	 */
   1330 #define	LOWER_LIMIT(val)	((val) - (val)/10 - 10)
   1331 #define	UPPER_LIMIT(val)	((val) + (val)/10 + 10)
   1332 	if (adv_pr->adv_pr_AdvValidRealTime) {
   1333 		if (adv_pr->adv_pr_AdvValidExpiration > 0 &&
   1334 		    (validtime <
   1335 		    LOWER_LIMIT(adv_pr->adv_pr_AdvValidExpiration) ||
   1336 		    validtime >
   1337 		    UPPER_LIMIT(adv_pr->adv_pr_AdvValidExpiration))) {
   1338 			logmsg(LOG_INFO, "RA from %s on %s inconsistent valid "
   1339 			    "lifetime for\n\tprefix %s/%u: received %d "
   1340 			    "configuration %d\n",
   1341 			    frombuf, pi->pi_name, prefixbuf,
   1342 			    adv_pr->adv_pr_prefix_len,
   1343 			    validtime, adv_pr->adv_pr_AdvValidExpiration);
   1344 		}
   1345 	} else {
   1346 		if (validtime != adv_pr->adv_pr_AdvValidLifetime) {
   1347 			logmsg(LOG_INFO, "RA from %s on %s inconsistent valid "
   1348 			    "lifetime for\n\tprefix %s/%u: received %d "
   1349 			    "configuration %d\n",
   1350 			    frombuf, pi->pi_name, prefixbuf,
   1351 			    adv_pr->adv_pr_prefix_len,
   1352 			    validtime, adv_pr->adv_pr_AdvValidLifetime);
   1353 		}
   1354 	}
   1355 
   1356 	if (adv_pr->adv_pr_AdvPreferredRealTime) {
   1357 		if (adv_pr->adv_pr_AdvPreferredExpiration > 0 &&
   1358 		    (preftime <
   1359 		    LOWER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration) ||
   1360 		    preftime >
   1361 		    UPPER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration))) {
   1362 			logmsg(LOG_INFO, "RA from %s on %s inconsistent "
   1363 			    "preferred lifetime for\n\tprefix %s/%u: "
   1364 			    "received %d configuration %d\n",
   1365 			    frombuf, pi->pi_name, prefixbuf,
   1366 			    adv_pr->adv_pr_prefix_len,
   1367 			    preftime, adv_pr->adv_pr_AdvPreferredExpiration);
   1368 		}
   1369 	} else {
   1370 		if (preftime != adv_pr->adv_pr_AdvPreferredLifetime) {
   1371 			logmsg(LOG_INFO, "RA from %s on %s inconsistent "
   1372 			    "preferred lifetime for\n\tprefix %s/%u: "
   1373 			    "received %d configuration %d\n",
   1374 			    frombuf, pi->pi_name, prefixbuf,
   1375 			    adv_pr->adv_pr_prefix_len,
   1376 			    preftime, adv_pr->adv_pr_AdvPreferredLifetime);
   1377 		}
   1378 	}
   1379 }
   1380 
   1381 /*
   1382  * Verify the received MTU against our own configuration.
   1383  */
   1384 static void
   1385 verify_mtu_opt(struct phyint *pi, uchar_t *opt, char *frombuf)
   1386 {
   1387 	struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt;
   1388 	uint32_t mtu;
   1389 
   1390 	if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) {
   1391 		logmsg(LOG_INFO, "mtu option from %s on %s wrong size "
   1392 		    "(%d bytes)\n",
   1393 		    frombuf, pi->pi_name,
   1394 		    8 * (int)mo->nd_opt_mtu_len);
   1395 		return;
   1396 	}
   1397 	mtu = ntohl(mo->nd_opt_mtu_mtu);
   1398 	if (pi->pi_AdvLinkMTU != 0 &&
   1399 	    pi->pi_AdvLinkMTU != mtu) {
   1400 		logmsg(LOG_INFO, "RA from %s on %s inconsistent MTU: "
   1401 		    "received %d configuration %d\n",
   1402 		    frombuf, pi->pi_name,
   1403 		    mtu, pi->pi_AdvLinkMTU);
   1404 	}
   1405 }
   1406 
   1407 /*
   1408  * Verify that all options have a non-zero length and that
   1409  * the options fit within the total length of the packet (optlen).
   1410  */
   1411 static boolean_t
   1412 verify_opt_len(struct nd_opt_hdr *opt, int optlen,
   1413     struct phyint *pi, struct sockaddr_in6 *from)
   1414 {
   1415 	while (optlen > 0) {
   1416 		if (opt->nd_opt_len == 0) {
   1417 			char abuf[INET6_ADDRSTRLEN];
   1418 
   1419 			(void) inet_ntop(AF_INET6,
   1420 			    (void *)&from->sin6_addr,
   1421 			    abuf, sizeof (abuf));
   1422 
   1423 			logmsg(LOG_INFO, "Zero length option type 0x%x "
   1424 			    "from %s on %s\n",
   1425 			    opt->nd_opt_type, abuf, pi->pi_name);
   1426 			return (_B_FALSE);
   1427 		}
   1428 		optlen -= 8 * opt->nd_opt_len;
   1429 		if (optlen < 0) {
   1430 			char abuf[INET6_ADDRSTRLEN];
   1431 
   1432 			(void) inet_ntop(AF_INET6,
   1433 			    (void *)&from->sin6_addr,
   1434 			    abuf, sizeof (abuf));
   1435 
   1436 			logmsg(LOG_INFO, "Too large option: type 0x%x len %u "
   1437 			    "from %s on %s\n",
   1438 			    opt->nd_opt_type, opt->nd_opt_len,
   1439 			    abuf, pi->pi_name);
   1440 			return (_B_FALSE);
   1441 		}
   1442 		opt = (struct nd_opt_hdr *)((char *)opt +
   1443 		    8 * opt->nd_opt_len);
   1444 	}
   1445 	return (_B_TRUE);
   1446 }
   1447 
   1448 /*
   1449  * Update IsRouter Flag for Host turning into a router or vice-versa.
   1450  */
   1451 static void
   1452 update_ra_flag(const struct phyint *pi, const struct sockaddr_in6 *from,
   1453     int isrouter)
   1454 {
   1455 	struct lifreq lifr;
   1456 	char abuf[INET6_ADDRSTRLEN];
   1457 	struct sockaddr_in6 *sin6;
   1458 
   1459 	/* check if valid flag is being set */
   1460 	if ((isrouter != NDF_ISROUTER_ON) &&
   1461 	    (isrouter != NDF_ISROUTER_OFF)) {
   1462 		logmsg(LOG_ERR, "update_ra_flag: Invalid IsRouter "
   1463 		    "flag %d\n", isrouter);
   1464 		return;
   1465 	}
   1466 
   1467 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr;
   1468 	bzero(sin6, sizeof (*sin6));
   1469 	sin6->sin6_family = AF_INET6;
   1470 	sin6->sin6_addr = from->sin6_addr;
   1471 
   1472 	(void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
   1473 
   1474 	if (ioctl(pi->pi_sock, SIOCLIFGETND, (char *)&lifr) < 0) {
   1475 		if (errno == ESRCH) {
   1476 			if (debug & D_IFSCAN) {
   1477 				logmsg(LOG_DEBUG,
   1478 "update_ra_flag: SIOCLIFGETND: nce doesn't exist, not setting IFF_ROUTER");
   1479 			}
   1480 		} else {
   1481 			logperror_pi(pi, "update_ra_flag: SIOCLIFGETND");
   1482 		}
   1483 	} else {
   1484 		/*
   1485 		 * The lif_nd_req structure has three state values to be used
   1486 		 * when changing/updating nces :
   1487 		 * lnr_state_create, lnr_state_same_lla, and lnr_state_diff_lla.
   1488 		 *
   1489 		 * In this case, we're updating an nce, without changing lla;
   1490 		 * so we set lnr_state_same_lla to ND_UNCHANGED, indicating that
   1491 		 * nce's state should not be affected by our flag change.
   1492 		 *
   1493 		 * The kernel implementation also expects the lnr_state_create
   1494 		 * field be always set, before processing ioctl request for NCE
   1495 		 * update.
   1496 		 * We use the state as STALE, while addressing the possibility
   1497 		 * of NCE deletion when ioctl with SIOCLIFGETND argument
   1498 		 * in earlier step is returned - further in such case we don't
   1499 		 * want to re-create the entry in the reachable state.
   1500 		 */
   1501 		lifr.lifr_nd.lnr_state_create = ND_STALE;
   1502 		lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED;
   1503 		lifr.lifr_nd.lnr_flags = isrouter;
   1504 		if ((ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr)) < 0) {
   1505 			logperror_pi(pi, "update_ra_flag: SIOCLIFSETND");
   1506 		} else {
   1507 			(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
   1508 			    abuf, sizeof (abuf));
   1509 			logmsg(LOG_INFO, "update_ra_flag: IsRouter flag "
   1510 			    "updated for %s\n", abuf);
   1511 		}
   1512 	}
   1513 }
   1514