xref: /titanic_52/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.c (revision ab5c384599c214af20872d1d5b10cfd4c6486116)
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 (_B_TRUE);
964 				}
965 			}
966 			tokenlen = TMP_TOKEN_BITS;
967 			token = &pi->pi_tmp_token;
968 		} else {
969 			tokenlen = pi->pi_token_length;
970 			token = &pi->pi_token;
971 		}
972 		if (pr->pr_prefix_len + tokenlen != IPV6_ABITS) {
973 			(void) inet_ntop(AF_INET6,
974 			    (void *)&from->sin6_addr,
975 			    abuf, sizeof (abuf));
976 			(void) inet_ntop(AF_INET6,
977 			    (void *)&po->nd_opt_pi_prefix,
978 			    pbuf, sizeof (pbuf));
979 			logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: "
980 			    "mismatched length %d token length %d\n",
981 			    pbuf, plen, abuf, pi->pi_name,
982 			    pr->pr_prefix_len, tokenlen);
983 			return (_B_TRUE);
984 		}
985 		for (i = 0; i < 16; i++) {
986 			/*
987 			 * prefix_create ensures that pr_prefix has all-zero
988 			 * bits after prefixlen.
989 			 */
990 			pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] |
991 			    token->s6_addr[i];
992 		}
993 		/*
994 		 * Check if any other physical interface has the same
995 		 * address configured already
996 		 */
997 		if ((other_pr = prefix_lookup_addr_match(pr)) != NULL) {
998 			/*
999 			 * Delete this prefix structure as kernel
1000 			 * does not allow duplicated addresses
1001 			 */
1002 
1003 			logmsg(LOG_ERR, "incoming_prefix_addrconf_process: "
1004 			    "Duplicate prefix  %s received on interface %s\n",
1005 			    inet_ntop(AF_INET6,
1006 			    (void *)&po->nd_opt_pi_prefix, abuf,
1007 			    sizeof (abuf)), pi->pi_name);
1008 			logmsg(LOG_ERR, "incoming_prefix_addrconf_process: "
1009 			    "Prefix already exists in interface %s\n",
1010 			    other_pr->pr_physical->pi_name);
1011 			if (new_prefix) {
1012 				prefix_delete(pr);
1013 				return (_B_FALSE);
1014 			}
1015 			/* Ignore for addrconf purposes */
1016 			validtime = preftime = 0;
1017 		}
1018 		if ((pr->pr_flags & IFF_TEMPORARY) && new_prefix) {
1019 			pr->pr_CreateTime = getcurrenttime() / MILLISEC;
1020 			if (debug & D_TMP)
1021 				logmsg(LOG_DEBUG,
1022 				    "created tmp addr(%s v %d p %d)\n",
1023 				    pr->pr_name, validtime, preftime);
1024 		}
1025 	}
1026 
1027 	if (validtime != 0)
1028 		pr->pr_state |= PR_AUTO;
1029 	else
1030 		pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED);
1031 	if (preftime != 0 || !(pr->pr_state & PR_AUTO))
1032 		pr->pr_state &= ~PR_DEPRECATED;
1033 	else
1034 		pr->pr_state |= PR_DEPRECATED;
1035 
1036 	/*
1037 	 * Convert from seconds to milliseconds avoiding overflow.
1038 	 * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1
1039 	 * (4 billion seconds - about 130 years) we will in fact time
1040 	 * out the prefix after 4 billion milliseconds - 46 days).
1041 	 * Thus the longest lifetime (apart from infinity) is 46 days.
1042 	 * Note that this ensures that PREFIX_INFINITY still means "forever".
1043 	 */
1044 	if (validtime >= PREFIX_INFINITY / MILLISEC)
1045 		pr->pr_ValidLifetime = PREFIX_INFINITY - 1;
1046 	else
1047 		pr->pr_ValidLifetime = validtime * MILLISEC;
1048 	if (preftime >= PREFIX_INFINITY / MILLISEC)
1049 		pr->pr_PreferredLifetime = PREFIX_INFINITY - 1;
1050 	else
1051 		pr->pr_PreferredLifetime = preftime * MILLISEC;
1052 	pr->pr_AutonomousFlag = _B_TRUE;
1053 
1054 	if (debug & D_PREFIX) {
1055 		logmsg(LOG_DEBUG, "incoming_prefix_addrconf_process(%s, %s/%u) "
1056 		    "valid %u pref %u\n",
1057 		    pr->pr_physical->pi_name,
1058 		    inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
1059 		    abuf, sizeof (abuf)), pr->pr_prefix_len,
1060 		    pr->pr_ValidLifetime, pr->pr_PreferredLifetime);
1061 	}
1062 
1063 	if (pr->pr_state & PR_AUTO) {
1064 		/* Take the min of the two timeouts by calling it twice */
1065 		if (pr->pr_ValidLifetime != 0)
1066 			timer_schedule(pr->pr_ValidLifetime);
1067 		if (pr->pr_PreferredLifetime != 0)
1068 			timer_schedule(pr->pr_PreferredLifetime);
1069 	}
1070 	if (pr->pr_kernel_state != pr->pr_state) {
1071 		/* Log a message when an addrconf prefix goes away */
1072 		if ((pr->pr_kernel_state & PR_AUTO) &&
1073 		    !(pr->pr_state & PR_AUTO)) {
1074 			char abuf[INET6_ADDRSTRLEN];
1075 
1076 			logmsg(LOG_WARNING, "Address removed due to zero "
1077 			    "valid lifetime %s\n",
1078 			    inet_ntop(AF_INET6, (void *)&pr->pr_address,
1079 			    abuf, sizeof (abuf)));
1080 		}
1081 		prefix_update_k(pr);
1082 	}
1083 	return (_B_TRUE);
1084 }
1085 
1086 /*
1087  * Process an MTU option received in a router advertisement.
1088  */
1089 static void
1090 incoming_mtu_opt(struct phyint *pi, uchar_t *opt,
1091     struct sockaddr_in6 *from)
1092 {
1093 	struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt;
1094 	struct lifreq lifr;
1095 	uint32_t mtu;
1096 
1097 	if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) {
1098 		char abuf[INET6_ADDRSTRLEN];
1099 
1100 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1101 		    abuf, sizeof (abuf));
1102 		logmsg(LOG_INFO, "mtu option from %s on %s wrong size "
1103 		    "(%d bytes)\n",
1104 		    abuf, pi->pi_name,
1105 		    8 * (int)mo->nd_opt_mtu_len);
1106 		return;
1107 	}
1108 	mtu = ntohl(mo->nd_opt_mtu_mtu);
1109 	if (pi->pi_LinkMTU == mtu)
1110 		return;	/* No change */
1111 	if (mtu > pi->pi_mtu) {
1112 		/* Can't exceed physical MTU */
1113 		char abuf[INET6_ADDRSTRLEN];
1114 
1115 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1116 		    abuf, sizeof (abuf));
1117 		logmsg(LOG_INFO, "mtu option from %s on %s too large "
1118 		    "MTU %d - %d\n", abuf, pi->pi_name, mtu, pi->pi_mtu);
1119 		return;
1120 	}
1121 	if (mtu < IPV6_MIN_MTU) {
1122 		char abuf[INET6_ADDRSTRLEN];
1123 
1124 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1125 		    abuf, sizeof (abuf));
1126 		logmsg(LOG_INFO, "mtu option from %s on %s too small "
1127 		    "MTU (%d)\n", abuf, pi->pi_name, mtu);
1128 		return;
1129 	}
1130 
1131 	pi->pi_LinkMTU = mtu;
1132 	(void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
1133 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
1134 	if (ioctl(pi->pi_sock, SIOCGLIFLNKINFO, (char *)&lifr) < 0) {
1135 		logperror_pi(pi, "incoming_mtu_opt: SIOCGLIFLNKINFO");
1136 		return;
1137 	}
1138 	lifr.lifr_ifinfo.lir_maxmtu = pi->pi_LinkMTU;
1139 	if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) {
1140 		logperror_pi(pi, "incoming_mtu_opt: SIOCSLIFLNKINFO");
1141 		return;
1142 	}
1143 }
1144 
1145 /*
1146  * Process a source link-layer address option received in a router
1147  * advertisement or solicitation.
1148  */
1149 static void
1150 incoming_lla_opt(struct phyint *pi, uchar_t *opt,
1151     struct sockaddr_in6 *from, int isrouter)
1152 {
1153 	struct nd_opt_lla *lo = (struct nd_opt_lla *)opt;
1154 	struct lifreq lifr;
1155 	struct sockaddr_in6 *sin6;
1156 	int max_content_len;
1157 
1158 	if (pi->pi_hdw_addr_len == 0)
1159 		return;
1160 
1161 	/*
1162 	 * Can't remove padding since it is link type specific.
1163 	 * However, we check against the length of our link-layer
1164 	 * address.
1165 	 * Note: assumes that all links have a fixed lengh address.
1166 	 */
1167 	max_content_len = lo->nd_opt_lla_len * 8 - sizeof (struct nd_opt_hdr);
1168 	if (max_content_len < pi->pi_hdw_addr_len ||
1169 	    (max_content_len >= 8 &&
1170 	    max_content_len - 7 > pi->pi_hdw_addr_len)) {
1171 		char abuf[INET6_ADDRSTRLEN];
1172 
1173 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1174 		    abuf, sizeof (abuf));
1175 		logmsg(LOG_INFO, "lla option from %s on %s too long with bad "
1176 		    "physaddr length (%d vs. %d bytes)\n",
1177 		    abuf, pi->pi_name,
1178 		    max_content_len, pi->pi_hdw_addr_len);
1179 		return;
1180 	}
1181 
1182 	lifr.lifr_nd.lnr_hdw_len = pi->pi_hdw_addr_len;
1183 	bcopy((char *)lo->nd_opt_lla_hdw_addr,
1184 	    (char *)lifr.lifr_nd.lnr_hdw_addr,
1185 	    lifr.lifr_nd.lnr_hdw_len);
1186 
1187 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr;
1188 	bzero(sin6, sizeof (struct sockaddr_in6));
1189 	sin6->sin6_family = AF_INET6;
1190 	sin6->sin6_addr = from->sin6_addr;
1191 
1192 	/*
1193 	 * Set IsRouter flag if RA; clear if RS.
1194 	 */
1195 	lifr.lifr_nd.lnr_state_create = ND_STALE;
1196 	lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED;
1197 	lifr.lifr_nd.lnr_state_diff_lla = ND_STALE;
1198 	lifr.lifr_nd.lnr_flags = isrouter;
1199 	(void) strncpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
1200 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
1201 	if (ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr) < 0) {
1202 		logperror_pi(pi, "incoming_lla_opt: SIOCLIFSETND");
1203 		return;
1204 	}
1205 }
1206 
1207 /*
1208  * Verify the content of the received router advertisement against our
1209  * own configuration as specified in RFC 2461.
1210  */
1211 static void
1212 verify_ra_consistency(struct phyint *pi, struct nd_router_advert *ra, int len,
1213     struct sockaddr_in6 *from)
1214 {
1215 	char frombuf[INET6_ADDRSTRLEN];
1216 	struct nd_opt_hdr *opt;
1217 	int optlen;
1218 	uint_t reachable, retrans;
1219 	boolean_t pktflag, myflag;
1220 
1221 	(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1222 	    frombuf, sizeof (frombuf));
1223 
1224 	if (ra->nd_ra_curhoplimit != 0 &&
1225 	    pi->pi_AdvCurHopLimit != 0 &&
1226 	    ra->nd_ra_curhoplimit != pi->pi_AdvCurHopLimit) {
1227 		logmsg(LOG_INFO, "RA from %s on %s inconsistent cur hop "
1228 		    "limit:\n\treceived %d configuration %d\n",
1229 		    frombuf, pi->pi_name,
1230 		    ra->nd_ra_curhoplimit, pi->pi_AdvCurHopLimit);
1231 	}
1232 
1233 	reachable = ntohl(ra->nd_ra_reachable);
1234 	if (reachable != 0 && pi->pi_AdvReachableTime != 0 &&
1235 	    reachable != pi->pi_AdvReachableTime) {
1236 		logmsg(LOG_INFO, "RA from %s on %s inconsistent reachable "
1237 		    "time:\n\treceived %d configuration %d\n",
1238 		    frombuf, pi->pi_name,
1239 		    reachable, pi->pi_AdvReachableTime);
1240 	}
1241 
1242 	retrans = ntohl(ra->nd_ra_retransmit);
1243 	if (retrans != 0 && pi->pi_AdvRetransTimer != 0 &&
1244 	    retrans != pi->pi_AdvRetransTimer) {
1245 		logmsg(LOG_INFO, "RA from %s on %s inconsistent retransmit "
1246 		    "timer:\n\treceived %d configuration %d\n",
1247 		    frombuf, pi->pi_name,
1248 		    retrans, pi->pi_AdvRetransTimer);
1249 	}
1250 
1251 	pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != 0);
1252 	myflag = (pi->pi_AdvManagedFlag != 0);
1253 	if (pktflag != myflag) {
1254 		logmsg(LOG_INFO, "RA from %s on %s inconsistent managed "
1255 		    "flag:\n\treceived %s configuration %s\n",
1256 		    frombuf, pi->pi_name,
1257 		    (pktflag ? "ON" : "OFF"),
1258 		    (myflag ? "ON" : "OFF"));
1259 	}
1260 	pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != 0);
1261 	myflag = (pi->pi_AdvOtherConfigFlag != 0);
1262 	if (pktflag != myflag) {
1263 		logmsg(LOG_INFO, "RA from %s on %s inconsistent other config "
1264 		    "flag:\n\treceived %s configuration %s\n",
1265 		    frombuf, pi->pi_name,
1266 		    (pktflag ? "ON" : "OFF"),
1267 		    (myflag ? "ON" : "OFF"));
1268 	}
1269 
1270 	/* Process any options */
1271 	len -= sizeof (struct nd_router_advert);
1272 	opt = (struct nd_opt_hdr *)&ra[1];
1273 	while (len >= sizeof (struct nd_opt_hdr)) {
1274 		optlen = opt->nd_opt_len * 8;
1275 		switch (opt->nd_opt_type) {
1276 		case ND_OPT_PREFIX_INFORMATION:
1277 			verify_prefix_opt(pi, (uchar_t *)opt, frombuf);
1278 			break;
1279 		case ND_OPT_MTU:
1280 			verify_mtu_opt(pi, (uchar_t *)opt, frombuf);
1281 			break;
1282 		default:
1283 			break;
1284 		}
1285 		opt = (struct nd_opt_hdr *)((char *)opt + optlen);
1286 		len -= optlen;
1287 	}
1288 }
1289 
1290 /*
1291  * Verify that the lifetimes and onlink/auto flags are consistent
1292  * with our settings.
1293  */
1294 static void
1295 verify_prefix_opt(struct phyint *pi, uchar_t *opt, char *frombuf)
1296 {
1297 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
1298 	int plen;
1299 	struct adv_prefix *adv_pr;
1300 	uint32_t validtime, preftime;
1301 	char prefixbuf[INET6_ADDRSTRLEN];
1302 	int pktflag, myflag;
1303 
1304 	if (8 * po->nd_opt_pi_len != sizeof (*po)) {
1305 		logmsg(LOG_INFO, "RA prefix option from %s on %s wrong size "
1306 		    "(%d bytes)\n",
1307 		    frombuf, pi->pi_name,
1308 		    8 * (int)po->nd_opt_pi_len);
1309 		return;
1310 	}
1311 	if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) {
1312 		logmsg(LOG_INFO, "RA from %s on %s contains link-local "
1313 		    "prefix - ignored\n",
1314 		    frombuf, pi->pi_name);
1315 		return;
1316 	}
1317 	plen = po->nd_opt_pi_prefix_len;
1318 	adv_pr = adv_prefix_lookup(pi, po->nd_opt_pi_prefix, plen);
1319 	if (adv_pr == NULL)
1320 		return;
1321 
1322 	/* Ignore prefixes which we do not advertise */
1323 	if (!adv_pr->adv_pr_AdvAutonomousFlag && !adv_pr->adv_pr_AdvOnLinkFlag)
1324 		return;
1325 	(void) inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix,
1326 	    prefixbuf, sizeof (prefixbuf));
1327 	pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) != 0);
1328 	myflag = (adv_pr->adv_pr_AdvAutonomousFlag != 0);
1329 	if (pktflag != myflag) {
1330 		logmsg(LOG_INFO,
1331 		    "RA from %s on %s inconsistent autonomous flag for \n\t"
1332 		    "prefix %s/%u: received %s configuration %s\n",
1333 		    frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len,
1334 		    (pktflag ? "ON" : "OFF"),
1335 		    (myflag ? "ON" : "OFF"));
1336 	}
1337 
1338 	pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) != 0);
1339 	myflag = (adv_pr->adv_pr_AdvOnLinkFlag != 0);
1340 	if (pktflag != myflag) {
1341 		logmsg(LOG_INFO, "RA from %s on %s inconsistent on link flag "
1342 		    "for \n\tprefix %s/%u: received %s configuration %s\n",
1343 		    frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len,
1344 		    (pktflag ? "ON" : "OFF"),
1345 		    (myflag ? "ON" : "OFF"));
1346 	}
1347 	validtime = ntohl(po->nd_opt_pi_valid_time);
1348 	preftime = ntohl(po->nd_opt_pi_preferred_time);
1349 
1350 	/*
1351 	 * Take into account variation for lifetimes decrementing
1352 	 * in real time. Allow +/- 10 percent and +/- 10 seconds.
1353 	 */
1354 #define	LOWER_LIMIT(val)	((val) - (val)/10 - 10)
1355 #define	UPPER_LIMIT(val)	((val) + (val)/10 + 10)
1356 	if (adv_pr->adv_pr_AdvValidRealTime) {
1357 		if (adv_pr->adv_pr_AdvValidExpiration > 0 &&
1358 		    (validtime <
1359 		    LOWER_LIMIT(adv_pr->adv_pr_AdvValidExpiration) ||
1360 		    validtime >
1361 		    UPPER_LIMIT(adv_pr->adv_pr_AdvValidExpiration))) {
1362 			logmsg(LOG_INFO, "RA from %s on %s inconsistent valid "
1363 			    "lifetime for\n\tprefix %s/%u: received %d "
1364 			    "configuration %d\n",
1365 			    frombuf, pi->pi_name, prefixbuf,
1366 			    adv_pr->adv_pr_prefix_len,
1367 			    validtime, adv_pr->adv_pr_AdvValidExpiration);
1368 		}
1369 	} else {
1370 		if (validtime != adv_pr->adv_pr_AdvValidLifetime) {
1371 			logmsg(LOG_INFO, "RA from %s on %s inconsistent valid "
1372 			    "lifetime for\n\tprefix %s/%u: received %d "
1373 			    "configuration %d\n",
1374 			    frombuf, pi->pi_name, prefixbuf,
1375 			    adv_pr->adv_pr_prefix_len,
1376 			    validtime, adv_pr->adv_pr_AdvValidLifetime);
1377 		}
1378 	}
1379 
1380 	if (adv_pr->adv_pr_AdvPreferredRealTime) {
1381 		if (adv_pr->adv_pr_AdvPreferredExpiration > 0 &&
1382 		    (preftime <
1383 		    LOWER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration) ||
1384 		    preftime >
1385 		    UPPER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration))) {
1386 			logmsg(LOG_INFO, "RA from %s on %s inconsistent "
1387 			    "preferred lifetime for\n\tprefix %s/%u: "
1388 			    "received %d configuration %d\n",
1389 			    frombuf, pi->pi_name, prefixbuf,
1390 			    adv_pr->adv_pr_prefix_len,
1391 			    preftime, adv_pr->adv_pr_AdvPreferredExpiration);
1392 		}
1393 	} else {
1394 		if (preftime != adv_pr->adv_pr_AdvPreferredLifetime) {
1395 			logmsg(LOG_INFO, "RA from %s on %s inconsistent "
1396 			    "preferred lifetime for\n\tprefix %s/%u: "
1397 			    "received %d configuration %d\n",
1398 			    frombuf, pi->pi_name, prefixbuf,
1399 			    adv_pr->adv_pr_prefix_len,
1400 			    preftime, adv_pr->adv_pr_AdvPreferredLifetime);
1401 		}
1402 	}
1403 }
1404 
1405 /*
1406  * Verify the received MTU against our own configuration.
1407  */
1408 static void
1409 verify_mtu_opt(struct phyint *pi, uchar_t *opt, char *frombuf)
1410 {
1411 	struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt;
1412 	uint32_t mtu;
1413 
1414 	if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) {
1415 		logmsg(LOG_INFO, "mtu option from %s on %s wrong size "
1416 		    "(%d bytes)\n",
1417 		    frombuf, pi->pi_name,
1418 		    8 * (int)mo->nd_opt_mtu_len);
1419 		return;
1420 	}
1421 	mtu = ntohl(mo->nd_opt_mtu_mtu);
1422 	if (pi->pi_AdvLinkMTU != 0 &&
1423 	    pi->pi_AdvLinkMTU != mtu) {
1424 		logmsg(LOG_INFO, "RA from %s on %s inconsistent MTU: "
1425 		    "received %d configuration %d\n",
1426 		    frombuf, pi->pi_name,
1427 		    mtu, pi->pi_AdvLinkMTU);
1428 	}
1429 }
1430 
1431 /*
1432  * Verify that all options have a non-zero length and that
1433  * the options fit within the total length of the packet (optlen).
1434  */
1435 static boolean_t
1436 verify_opt_len(struct nd_opt_hdr *opt, int optlen,
1437     struct phyint *pi, struct sockaddr_in6 *from)
1438 {
1439 	while (optlen > 0) {
1440 		if (opt->nd_opt_len == 0) {
1441 			char abuf[INET6_ADDRSTRLEN];
1442 
1443 			(void) inet_ntop(AF_INET6,
1444 			    (void *)&from->sin6_addr,
1445 			    abuf, sizeof (abuf));
1446 
1447 			logmsg(LOG_INFO, "Zero length option type 0x%x "
1448 			    "from %s on %s\n",
1449 			    opt->nd_opt_type, abuf, pi->pi_name);
1450 			return (_B_FALSE);
1451 		}
1452 		optlen -= 8 * opt->nd_opt_len;
1453 		if (optlen < 0) {
1454 			char abuf[INET6_ADDRSTRLEN];
1455 
1456 			(void) inet_ntop(AF_INET6,
1457 			    (void *)&from->sin6_addr,
1458 			    abuf, sizeof (abuf));
1459 
1460 			logmsg(LOG_INFO, "Too large option: type 0x%x len %u "
1461 			    "from %s on %s\n",
1462 			    opt->nd_opt_type, opt->nd_opt_len,
1463 			    abuf, pi->pi_name);
1464 			return (_B_FALSE);
1465 		}
1466 		opt = (struct nd_opt_hdr *)((char *)opt +
1467 		    8 * opt->nd_opt_len);
1468 	}
1469 	return (_B_TRUE);
1470 }
1471 
1472 /*
1473  * Update IsRouter Flag for Host turning into a router or vice-versa.
1474  */
1475 static void
1476 update_ra_flag(const struct phyint *pi, const struct sockaddr_in6 *from,
1477     int isrouter)
1478 {
1479 	struct lifreq lifr;
1480 	char abuf[INET6_ADDRSTRLEN];
1481 	struct sockaddr_in6 *sin6;
1482 
1483 	/* check if valid flag is being set */
1484 	if ((isrouter != NDF_ISROUTER_ON) &&
1485 	    (isrouter != NDF_ISROUTER_OFF)) {
1486 		logmsg(LOG_ERR, "update_ra_flag: Invalid IsRouter "
1487 		    "flag %d\n", isrouter);
1488 		return;
1489 	}
1490 
1491 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr;
1492 	bzero(sin6, sizeof (*sin6));
1493 	sin6->sin6_family = AF_INET6;
1494 	sin6->sin6_addr = from->sin6_addr;
1495 
1496 	(void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
1497 
1498 	if (ioctl(pi->pi_sock, SIOCLIFGETND, (char *)&lifr) < 0) {
1499 		if (errno == ESRCH) {
1500 			if (debug & D_IFSCAN) {
1501 				logmsg(LOG_DEBUG,
1502 "update_ra_flag: SIOCLIFGETND: nce doesn't exist, not setting IFF_ROUTER");
1503 			}
1504 		} else {
1505 			logperror_pi(pi, "update_ra_flag: SIOCLIFGETND");
1506 		}
1507 	} else {
1508 		/*
1509 		 * The lif_nd_req structure has three state values to be used
1510 		 * when changing/updating nces :
1511 		 * lnr_state_create, lnr_state_same_lla, and lnr_state_diff_lla.
1512 		 *
1513 		 * In this case, we're updating an nce, without changing lla;
1514 		 * so we set lnr_state_same_lla to ND_UNCHANGED, indicating that
1515 		 * nce's state should not be affected by our flag change.
1516 		 *
1517 		 * The kernel implementation also expects the lnr_state_create
1518 		 * field be always set, before processing ioctl request for NCE
1519 		 * update.
1520 		 * We use the state as STALE, while addressing the possibility
1521 		 * of NCE deletion when ioctl with SIOCLIFGETND argument
1522 		 * in earlier step is returned - further in such case we don't
1523 		 * want to re-create the entry in the reachable state.
1524 		 */
1525 		lifr.lifr_nd.lnr_state_create = ND_STALE;
1526 		lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED;
1527 		lifr.lifr_nd.lnr_flags = isrouter;
1528 		if ((ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr)) < 0) {
1529 			logperror_pi(pi, "update_ra_flag: SIOCLIFSETND");
1530 		} else {
1531 			(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1532 			    abuf, sizeof (abuf));
1533 			logmsg(LOG_INFO, "update_ra_flag: IsRouter flag "
1534 			    "updated for %s\n", abuf);
1535 		}
1536 	}
1537 }
1538