xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/ndp.c (revision d1e631af56641f21cde1f1efe3a9623ff9d6ee7c)
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 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
29  */
30 
31 #include "defs.h"
32 #include "tables.h"
33 
34 #include <sys/sysmacros.h>
35 
36 #include <dhcpagent_ipc.h>
37 #include <dhcpagent_util.h>
38 
39 static boolean_t verify_opt_len(struct nd_opt_hdr *opt, int optlen,
40 		    struct phyint *pi, struct sockaddr_in6 *from);
41 
42 static void	incoming_rs(struct phyint *pi, struct nd_router_solicit *rs,
43 		    int len, struct sockaddr_in6 *from);
44 
45 void		incoming_ra(struct phyint *pi, struct nd_router_advert *ra,
46 		    int len, struct sockaddr_in6 *from, boolean_t loopback);
47 static void	incoming_prefix_opt(struct phyint *pi, uchar_t *opt,
48 		    struct sockaddr_in6 *from, boolean_t loopback);
49 static void	incoming_prefix_onlink(struct phyint *pi, uchar_t *opt);
50 void		incoming_prefix_onlink_process(struct prefix *pr,
51 		    uchar_t *opt);
52 static void	incoming_prefix_stateful(struct phyint *, uchar_t *);
53 static boolean_t	incoming_prefix_addrconf(struct phyint *pi,
54 		    uchar_t *opt, struct sockaddr_in6 *from,
55 		    boolean_t loopback);
56 boolean_t	incoming_prefix_addrconf_process(struct phyint *pi,
57 		    struct prefix *pr, uchar_t *opt,
58 		    struct sockaddr_in6 *from, boolean_t loopback,
59 		    boolean_t new_prefix);
60 static void	incoming_mtu_opt(struct phyint *pi, uchar_t *opt,
61 		    struct sockaddr_in6 *from);
62 static void	incoming_lla_opt(struct phyint *pi, uchar_t *opt,
63 		    struct sockaddr_in6 *from, int isrouter);
64 
65 static void	verify_ra_consistency(struct phyint *pi,
66 		    struct nd_router_advert *ra,
67 		    int len, struct sockaddr_in6 *from);
68 static void	verify_prefix_opt(struct phyint *pi, uchar_t *opt,
69 		    char *frombuf);
70 static void	verify_mtu_opt(struct phyint *pi, uchar_t *opt,
71 		    char *frombuf);
72 
73 static void	update_ra_flag(const struct phyint *pi,
74 		    const struct sockaddr_in6 *from, int isrouter);
75 
76 /*
77  * Return a pointer to the specified option buffer.
78  * If not found return NULL.
79  */
80 static void *
81 find_ancillary(struct msghdr *msg, int cmsg_type)
82 {
83 	struct cmsghdr *cmsg;
84 
85 	for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
86 	    cmsg = CMSG_NXTHDR(msg, cmsg)) {
87 		if (cmsg->cmsg_level == IPPROTO_IPV6 &&
88 		    cmsg->cmsg_type == cmsg_type) {
89 			return (CMSG_DATA(cmsg));
90 		}
91 	}
92 	return (NULL);
93 }
94 
95 void
96 in_data(struct phyint *pi)
97 {
98 	struct sockaddr_in6 from;
99 	struct icmp6_hdr *icmp;
100 	struct nd_router_solicit *rs;
101 	struct nd_router_advert *ra;
102 	static uint64_t in_packet[(IP_MAXPACKET + 1)/8];
103 	static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8];
104 	int len;
105 	char abuf[INET6_ADDRSTRLEN];
106 	const char *msgbuf;
107 	struct msghdr msg;
108 	struct iovec iov;
109 	uchar_t *opt;
110 	uint_t hoplimit;
111 
112 	iov.iov_base = (char *)in_packet;
113 	iov.iov_len = sizeof (in_packet);
114 	msg.msg_iov = &iov;
115 	msg.msg_iovlen = 1;
116 	msg.msg_name = (struct sockaddr *)&from;
117 	msg.msg_namelen = sizeof (from);
118 	msg.msg_control = ancillary_data;
119 	msg.msg_controllen = sizeof (ancillary_data);
120 
121 	if ((len = recvmsg(pi->pi_sock, &msg, 0)) < 0) {
122 		logperror_pi(pi, "in_data: recvfrom");
123 		return;
124 	}
125 	if (len == 0)
126 		return;
127 
128 	if (inet_ntop(AF_INET6, (void *)&from.sin6_addr,
129 	    abuf, sizeof (abuf)) == NULL)
130 		msgbuf = "Unspecified Router";
131 	else
132 		msgbuf = abuf;
133 
134 	/* Ignore packets > 64k or control buffers that don't fit */
135 	if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
136 		if (debug & D_PKTBAD) {
137 			logmsg(LOG_DEBUG, "Truncated message: msg_flags 0x%x "
138 			    "from %s\n", msg.msg_flags, msgbuf);
139 		}
140 		return;
141 	}
142 
143 	icmp = (struct icmp6_hdr *)in_packet;
144 
145 	if (len < ICMP6_MINLEN) {
146 		logmsg(LOG_INFO, "Too short ICMP packet: %d bytes "
147 		    "from %s on %s\n",
148 		    len, msgbuf, pi->pi_name);
149 		return;
150 	}
151 
152 	opt = find_ancillary(&msg, IPV6_HOPLIMIT);
153 	if (opt == NULL) {
154 		/* Unknown hoplimit - must drop */
155 		logmsg(LOG_INFO, "Unknown hop limit from %s on %s\n",
156 		    msgbuf, pi->pi_name);
157 		return;
158 	}
159 	hoplimit = *(uint_t *)opt;
160 	opt = find_ancillary(&msg, IPV6_RTHDR);
161 	if (opt != NULL) {
162 		/* Can't allow routing headers in ND messages */
163 		logmsg(LOG_INFO, "ND message with routing header "
164 		    "from %s on %s\n",
165 		    msgbuf, pi->pi_name);
166 		return;
167 	}
168 	switch (icmp->icmp6_type) {
169 	case ND_ROUTER_SOLICIT:
170 		if (!pi->pi_AdvSendAdvertisements)
171 			return;
172 		if (pi->pi_flags & IFF_NORTEXCH) {
173 			if (debug & D_PKTIN) {
174 				logmsg(LOG_DEBUG, "Ignore received RS packet "
175 				    "on %s (no route exchange on interface)\n",
176 				    pi->pi_name);
177 			}
178 			return;
179 		}
180 
181 		/*
182 		 * Assumes that the kernel has verified the AH (if present)
183 		 * and the ICMP checksum.
184 		 */
185 		if (hoplimit != IPV6_MAX_HOPS) {
186 			logmsg(LOG_DEBUG, "RS hop limit: %d from %s on %s\n",
187 			    hoplimit, msgbuf, pi->pi_name);
188 			return;
189 		}
190 
191 		if (icmp->icmp6_code != 0) {
192 			logmsg(LOG_INFO, "RS code: %d from %s on %s\n",
193 			    icmp->icmp6_code, msgbuf, pi->pi_name);
194 			return;
195 		}
196 
197 		if (len < sizeof (struct nd_router_solicit)) {
198 			logmsg(LOG_INFO, "RS too short: %d bytes "
199 			    "from %s on %s\n",
200 			    len, msgbuf, pi->pi_name);
201 			return;
202 		}
203 		rs = (struct nd_router_solicit *)icmp;
204 		if (len > sizeof (struct nd_router_solicit)) {
205 			if (!verify_opt_len((struct nd_opt_hdr *)&rs[1],
206 			    len - sizeof (struct nd_router_solicit), pi, &from))
207 				return;
208 		}
209 		if (debug & D_PKTIN) {
210 			print_route_sol("Received valid solicit from ", pi,
211 			    rs, len, &from);
212 		}
213 		incoming_rs(pi, rs, len, &from);
214 		break;
215 
216 	case ND_ROUTER_ADVERT:
217 		if (IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr)) {
218 			/*
219 			 * Router advt. must have address!
220 			 * Logging the news and returning.
221 			 */
222 			logmsg(LOG_DEBUG,
223 			    "Router's address unspecified in advertisement\n");
224 			return;
225 		}
226 		if (pi->pi_flags & IFF_NORTEXCH) {
227 			if (debug & D_PKTIN) {
228 				logmsg(LOG_DEBUG, "Ignore received RA packet "
229 				    "on %s (no route exchange on interface)\n",
230 				    pi->pi_name);
231 			}
232 			return;
233 		}
234 
235 		/*
236 		 * Assumes that the kernel has verified the AH (if present)
237 		 * and the ICMP checksum.
238 		 */
239 		if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
240 			logmsg(LOG_DEBUG, "RA from %s - not link local on %s\n",
241 			    msgbuf, pi->pi_name);
242 			return;
243 		}
244 
245 		if (hoplimit != IPV6_MAX_HOPS) {
246 			logmsg(LOG_INFO, "RA hop limit: %d from %s on %s\n",
247 			    hoplimit, msgbuf, pi->pi_name);
248 			return;
249 		}
250 
251 		if (icmp->icmp6_code != 0) {
252 			logmsg(LOG_INFO, "RA code: %d from %s on %s\n",
253 			    icmp->icmp6_code, msgbuf, pi->pi_name);
254 			return;
255 		}
256 
257 		if (len < sizeof (struct nd_router_advert)) {
258 			logmsg(LOG_INFO, "RA too short: %d bytes "
259 			    "from %s on %s\n",
260 			    len, msgbuf, pi->pi_name);
261 			return;
262 		}
263 		ra = (struct nd_router_advert *)icmp;
264 		if (len > sizeof (struct nd_router_advert)) {
265 			if (!verify_opt_len((struct nd_opt_hdr *)&ra[1],
266 			    len - sizeof (struct nd_router_advert), pi, &from))
267 				return;
268 		}
269 		if (debug & D_PKTIN) {
270 			print_route_adv("Received valid advert from ", pi,
271 			    ra, len, &from);
272 		}
273 		if (pi->pi_AdvSendAdvertisements)
274 			verify_ra_consistency(pi, ra, len, &from);
275 		else
276 			incoming_ra(pi, ra, len, &from, _B_FALSE);
277 		break;
278 	}
279 }
280 
281 /*
282  * Process a received router solicitation.
283  * Check for source link-layer address option and check if it
284  * is time to advertise.
285  */
286 static void
287 incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, int len,
288     struct sockaddr_in6 *from)
289 {
290 	struct nd_opt_hdr *opt;
291 	int optlen;
292 
293 	/* Process any options */
294 	len -= sizeof (struct nd_router_solicit);
295 	opt = (struct nd_opt_hdr *)&rs[1];
296 	while (len >= sizeof (struct nd_opt_hdr)) {
297 		optlen = opt->nd_opt_len * 8;
298 		switch (opt->nd_opt_type) {
299 		case ND_OPT_SOURCE_LINKADDR:
300 			incoming_lla_opt(pi, (uchar_t *)opt,
301 			    from, NDF_ISROUTER_OFF);
302 			break;
303 		default:
304 			break;
305 		}
306 		opt = (struct nd_opt_hdr *)((char *)opt + optlen);
307 		len -= optlen;
308 	}
309 	/* Simple algorithm: treat unicast and multicast RSs the same */
310 	check_to_advertise(pi, RECEIVED_SOLICIT);
311 }
312 
313 /*
314  * Function that sends commands to dhcpagent daemon.
315  */
316 int
317 dhcp_op(struct phyint *pi, int type)
318 {
319 	dhcp_ipc_request_t	*request;
320 	dhcp_ipc_reply_t	*reply	= NULL;
321 	int			error;
322 
323 	request = dhcp_ipc_alloc_request(type | DHCP_V6, pi->pi_name, NULL, 0,
324 	    DHCP_TYPE_NONE);
325 	if (request == NULL) {
326 		logmsg(LOG_ERR, "dhcp_op: out of memory\n");
327 		/* make sure we try again next time there's a chance */
328 		if (type != DHCP_RELEASE) {
329 			pi->pi_ra_flags &=
330 			    ~ND_RA_FLAG_MANAGED & ~ND_RA_FLAG_OTHER;
331 		}
332 		return (DHCP_IPC_E_MEMORY);
333 	}
334 
335 	error = dhcp_ipc_make_request(request, &reply, 0);
336 	free(request);
337 	if (error != 0) {
338 		logmsg(LOG_ERR, "could not send request to dhcpagent: "
339 		    "%s: %s\n", pi->pi_name, dhcp_ipc_strerror(error));
340 		return (error);
341 	}
342 
343 	error = reply->return_code;
344 	free(reply);
345 
346 	return (error);
347 }
348 
349 /*
350  * Start up DHCPv6 on a given physical interface. Does not wait for
351  * a message to be returned from the daemon.
352  */
353 void
354 start_dhcp(struct phyint *pi)
355 {
356 	int	error;
357 	int	type;
358 
359 	if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) {
360 		logmsg(LOG_ERR, "unable to start %s\n", DHCP_AGENT_PATH);
361 		/* make sure we try again next time there's a chance */
362 		pi->pi_ra_flags &= ~ND_RA_FLAG_MANAGED & ~ND_RA_FLAG_OTHER;
363 		return;
364 	}
365 
366 	else if (pi->pi_ra_flags & ND_RA_FLAG_MANAGED)
367 		type = DHCP_START;
368 	else
369 		type = DHCP_INFORM;
370 
371 	error = dhcp_op(pi, type);
372 	/*
373 	 * Timeout is considered to be "success" because we don't wait for DHCP
374 	 * to do its exchange.
375 	 */
376 	if (error != DHCP_IPC_SUCCESS && error != DHCP_IPC_E_RUNNING &&
377 	    error != DHCP_IPC_E_TIMEOUT) {
378 		logmsg(LOG_ERR, "Error in dhcpagent: %s: %s\n",
379 		    pi->pi_name, dhcp_ipc_strerror(error));
380 	}
381 }
382 
383 /*
384  * Release the acquired DHCPv6 lease on a given physical interface.
385  * Does not wait for a message to be returned from the daemon.
386  */
387 void
388 release_dhcp(struct phyint *pi)
389 {
390 	int	error;
391 	int	type;
392 
393 	type = DHCP_RELEASE;
394 retry:
395 	error = dhcp_op(pi, type);
396 	if (error != DHCP_IPC_SUCCESS && error != DHCP_IPC_E_RUNNING &&
397 	    error != DHCP_IPC_E_TIMEOUT) {
398 		if (type == DHCP_RELEASE && error == DHCP_IPC_E_OUTSTATE) {
399 			/*
400 			 * Drop the dhcp control if we cannot release it.
401 			 */
402 			type = DHCP_DROP;
403 			goto retry;
404 		}
405 		logmsg(LOG_ERR, "Error in dhcpagent: %s: %s\n",
406 		    pi->pi_name, dhcp_ipc_strerror(error));
407 	}
408 }
409 
410 /*
411  * Globals to check if we're seeing unusual hop counts in Router
412  * Advertisements (RAs).  We record the hopcounts in the kernel using
413  * SIOCSLIFLNKINFO, but the kernel ignores these when actually setting IPv6
414  * hop counts for packets.
415  *
416  * RFC 3756 does mention the possibility of an adversary throttling down
417  * hopcounts using unsolicited RAs.  These variables can be tuned with 'mdb -p'
418  * to reduce/increase our logging threshholds.
419  */
420 /* Really a boolean... if set, also log the offending sending address. */
421 int bad_hopcount_record_addr = 0;
422 /* Anything less triggers a warning.  Set to 0 to disable. */
423 int bad_hopcount_threshhold = 16;
424 /* Number of packets received below the threshhold. */
425 uint64_t bad_hopcount_packets;
426 
427 /*
428  * Process a received router advertisement.
429  * Called both when packets arrive as well as when we send RAs.
430  * In the latter case 'loopback' is set.
431  */
432 void
433 incoming_ra(struct phyint *pi, struct nd_router_advert *ra, int len,
434     struct sockaddr_in6 *from, boolean_t loopback)
435 {
436 	struct nd_opt_hdr *opt;
437 	int optlen;
438 	struct lifreq lifr;
439 	boolean_t set_needed = _B_FALSE;
440 	struct router *dr;
441 	uint16_t router_lifetime;
442 	uint_t reachable, retrans;
443 	boolean_t reachable_time_changed = _B_FALSE;
444 	boolean_t slla_opt_present	 = _B_FALSE;
445 
446 	if (no_loopback && loopback)
447 		return;
448 
449 	bzero(&lifr, sizeof (lifr));
450 	(void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
451 
452 	if (ra->nd_ra_curhoplimit != CURHOP_UNSPECIFIED &&
453 	    ra->nd_ra_curhoplimit != pi->pi_CurHopLimit) {
454 		pi->pi_CurHopLimit = ra->nd_ra_curhoplimit;
455 		lifr.lifr_ifinfo.lir_maxhops = pi->pi_CurHopLimit;
456 		set_needed = _B_TRUE;
457 
458 		if (pi->pi_CurHopLimit < bad_hopcount_threshhold) {
459 			char abuf[INET6_ADDRSTRLEN];
460 
461 			bad_hopcount_packets++;
462 			logmsg(LOG_ALERT,
463 			    "Low hopcount %d received on %s%s%s\n",
464 			    pi->pi_CurHopLimit, pi->pi_name,
465 			    bad_hopcount_record_addr ? " from " : "",
466 			    bad_hopcount_record_addr ?
467 			    inet_ntop(AF_INET6, &from->sin6_addr, abuf,
468 			    INET6_ADDRSTRLEN) : "");
469 		}
470 	}
471 
472 	reachable = ntohl(ra->nd_ra_reachable);
473 	if (reachable != 0 &&
474 	    reachable != pi->pi_BaseReachableTime) {
475 		pi->pi_BaseReachableTime = reachable;
476 		reachable_time_changed = _B_TRUE;
477 	}
478 
479 	if (pi->pi_reach_time_since_random < MIN_REACH_RANDOM_INTERVAL ||
480 	    reachable_time_changed) {
481 		phyint_reach_random(pi, _B_FALSE);
482 		set_needed = _B_TRUE;
483 	}
484 	lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime;
485 
486 	retrans = ntohl(ra->nd_ra_retransmit);
487 	if (retrans != 0 &&
488 	    pi->pi_RetransTimer != retrans) {
489 		pi->pi_RetransTimer = retrans;
490 		lifr.lifr_ifinfo.lir_reachretrans = pi->pi_RetransTimer;
491 		set_needed = _B_TRUE;
492 	}
493 
494 	if (set_needed) {
495 		if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) {
496 			logperror_pi(pi, "incoming_ra: SIOCSLIFLNKINFO");
497 			return;
498 		}
499 	}
500 
501 	/*
502 	 * If the "managed" flag is set, then just assume that the "other" flag
503 	 * is set as well.  It's not legal to get addresses alone without
504 	 * getting other data.
505 	 */
506 	if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
507 		ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
508 
509 	/*
510 	 * If either the "managed" or "other" bits have turned on, then it's
511 	 * now time to invoke DHCP.  If only the "other" bit is set, then don't
512 	 * get addresses via DHCP; only "other" data.  If "managed" is set,
513 	 * then we must always get both addresses and "other" data.
514 	 */
515 	if (pi->pi_autoconf && pi->pi_stateful &&
516 	    (ra->nd_ra_flags_reserved & ~pi->pi_ra_flags &
517 	    (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER))) {
518 		if (debug & D_DHCP) {
519 			logmsg(LOG_DEBUG,
520 			    "incoming_ra: trigger dhcp %s on %s\n",
521 			    (ra->nd_ra_flags_reserved & ~pi->pi_ra_flags &
522 			    ND_RA_FLAG_MANAGED) ? "MANAGED" : "OTHER",
523 			    pi->pi_name);
524 		}
525 		pi->pi_ra_flags |= ra->nd_ra_flags_reserved;
526 		start_dhcp(pi);
527 	}
528 
529 	/* Skip default router code if sent from ourselves */
530 	if (!loopback) {
531 		/* Find and update or add default router in list */
532 		dr = router_lookup(pi, from->sin6_addr);
533 		router_lifetime = ntohs(ra->nd_ra_router_lifetime);
534 		if (dr == NULL) {
535 			if (router_lifetime != 0) {
536 				dr = router_create(pi, from->sin6_addr,
537 				    MILLISEC * router_lifetime);
538 				timer_schedule(dr->dr_lifetime);
539 			}
540 		} else {
541 			dr->dr_lifetime = MILLISEC * router_lifetime;
542 			if (dr->dr_lifetime != 0)
543 				timer_schedule(dr->dr_lifetime);
544 			if ((dr->dr_lifetime != 0 && !dr->dr_inkernel) ||
545 			    (dr->dr_lifetime == 0 && dr->dr_inkernel))
546 				router_update_k(dr);
547 		}
548 	}
549 	/* Process any options */
550 	len -= sizeof (struct nd_router_advert);
551 	opt = (struct nd_opt_hdr *)&ra[1];
552 	while (len >= sizeof (struct nd_opt_hdr)) {
553 		optlen = opt->nd_opt_len * 8;
554 		switch (opt->nd_opt_type) {
555 		case ND_OPT_PREFIX_INFORMATION:
556 			incoming_prefix_opt(pi, (uchar_t *)opt, from,
557 			    loopback);
558 			break;
559 		case ND_OPT_MTU:
560 			incoming_mtu_opt(pi, (uchar_t *)opt, from);
561 			break;
562 		case ND_OPT_SOURCE_LINKADDR:
563 			/* skip lla option if sent from ourselves! */
564 			if (!loopback) {
565 				incoming_lla_opt(pi, (uchar_t *)opt,
566 				    from, NDF_ISROUTER_ON);
567 				slla_opt_present = _B_TRUE;
568 			}
569 			break;
570 		default:
571 			break;
572 		}
573 		opt = (struct nd_opt_hdr *)((char *)opt + optlen);
574 		len -= optlen;
575 	}
576 	if (!loopback && !slla_opt_present)
577 		update_ra_flag(pi, from, NDF_ISROUTER_ON);
578 	/* Stop sending solicitations */
579 	check_to_solicit(pi, SOLICIT_DONE);
580 }
581 
582 /*
583  * Process a received prefix option.
584  * Unless addrconf is turned off we process both the addrconf and the
585  * onlink aspects of the prefix option.
586  *
587  * Note that when a flag (onlink or auto) is turned off we do nothing -
588  * the prefix will time out.
589  */
590 static void
591 incoming_prefix_opt(struct phyint *pi, uchar_t *opt,
592     struct sockaddr_in6 *from, boolean_t loopback)
593 {
594 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
595 	boolean_t	good_prefix = _B_TRUE;
596 
597 	if (8 * po->nd_opt_pi_len != sizeof (*po)) {
598 		char abuf[INET6_ADDRSTRLEN];
599 
600 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
601 		    abuf, sizeof (abuf));
602 		logmsg(LOG_INFO, "prefix option from %s on %s wrong size "
603 		    "(%d bytes)\n",
604 		    abuf, pi->pi_name,
605 		    8 * (int)po->nd_opt_pi_len);
606 		return;
607 	}
608 	if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) {
609 		char abuf[INET6_ADDRSTRLEN];
610 
611 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
612 		    abuf, sizeof (abuf));
613 		logmsg(LOG_INFO, "RA from %s on %s contains link-local prefix "
614 		    "- ignored\n",
615 		    abuf, pi->pi_name);
616 		return;
617 	}
618 	if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) &&
619 	    pi->pi_stateless && pi->pi_autoconf) {
620 		good_prefix = incoming_prefix_addrconf(pi, opt, from, loopback);
621 	}
622 	if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) &&
623 	    good_prefix) {
624 		incoming_prefix_onlink(pi, opt);
625 	}
626 	if (pi->pi_stateful && pi->pi_autoconf)
627 		incoming_prefix_stateful(pi, opt);
628 }
629 
630 /*
631  * Process prefix options with the onlink flag set.
632  *
633  * If there are no routers ndpd will add an onlink
634  * default route which will allow communication
635  * between neighbors.
636  *
637  * This function needs to loop to find the same prefix multiple times
638  * as if a failover happened earlier, the addresses belonging to
639  * a different interface may be found here on this interface.
640  */
641 static void
642 incoming_prefix_onlink(struct phyint *pi, uchar_t *opt)
643 {
644 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
645 	int plen;
646 	struct prefix *pr;
647 	uint32_t validtime;	/* Without 2 hour rule */
648 	boolean_t found_one = _B_FALSE;
649 
650 	plen = po->nd_opt_pi_prefix_len;
651 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
652 		if (pr->pr_prefix_len == plen &&
653 		    prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) {
654 			/* Exclude static prefixes */
655 			if (pr->pr_state & PR_STATIC)
656 				continue;
657 			found_one = _B_TRUE;
658 			incoming_prefix_onlink_process(pr, opt);
659 		}
660 	}
661 
662 	validtime = ntohl(po->nd_opt_pi_valid_time);
663 	/*
664 	 * If we have found a matching prefix already or validtime
665 	 * is zero, we have nothing to do.
666 	 */
667 	if (validtime == 0 || found_one)
668 		return;
669 	pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0);
670 	if (pr == NULL)
671 		return;
672 	incoming_prefix_onlink_process(pr, opt);
673 }
674 
675 void
676 incoming_prefix_onlink_process(struct prefix *pr, uchar_t *opt)
677 {
678 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
679 	uint32_t validtime;	/* Without 2 hour rule */
680 	char abuf[INET6_ADDRSTRLEN];
681 
682 	validtime = ntohl(po->nd_opt_pi_valid_time);
683 	if (validtime != 0)
684 		pr->pr_state |= PR_ONLINK;
685 	else
686 		pr->pr_state &= ~PR_ONLINK;
687 
688 	/*
689 	 * Convert from seconds to milliseconds avoiding overflow.
690 	 * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1
691 	 * (4 billion seconds - about 130 years) we will in fact time
692 	 * out the prefix after 4 billion milliseconds - 46 days).
693 	 * Thus the longest lifetime (apart from infinity) is 46 days.
694 	 * Note that this ensures that PREFIX_INFINITY still means "forever".
695 	 */
696 	if (pr->pr_flags & IFF_TEMPORARY) {
697 		pr->pr_OnLinkLifetime = pr->pr_ValidLifetime;
698 	} else {
699 		if (validtime >= PREFIX_INFINITY / MILLISEC)
700 			pr->pr_OnLinkLifetime = PREFIX_INFINITY - 1;
701 		else
702 			pr->pr_OnLinkLifetime = validtime * MILLISEC;
703 	}
704 	pr->pr_OnLinkFlag = _B_TRUE;
705 	if (debug & (D_PREFIX|D_TMP)) {
706 		logmsg(LOG_DEBUG, "incoming_prefix_onlink_process(%s, %s/%u) "
707 		    "onlink %u state 0x%x, kstate 0x%x\n",
708 		    pr->pr_name, inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
709 		    abuf, sizeof (abuf)), pr->pr_prefix_len,
710 		    pr->pr_OnLinkLifetime, pr->pr_state, pr->pr_kernel_state);
711 	}
712 
713 	if (pr->pr_kernel_state != pr->pr_state) {
714 		prefix_update_k(pr);
715 	}
716 
717 	if (pr->pr_OnLinkLifetime != 0)
718 		timer_schedule(pr->pr_OnLinkLifetime);
719 }
720 
721 /*
722  * Process all prefix options by locating the DHCPv6-configured interfaces, and
723  * applying the netmasks as needed.
724  */
725 static void
726 incoming_prefix_stateful(struct phyint *pi, uchar_t *opt)
727 {
728 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
729 	struct prefix *pr;
730 	boolean_t foundpref;
731 	char abuf[INET6_ADDRSTRLEN];
732 
733 	/* Make sure it's a valid prefix. */
734 	if (ntohl(po->nd_opt_pi_valid_time) == 0) {
735 		if (debug & D_DHCP)
736 			logmsg(LOG_DEBUG, "incoming_prefix_stateful: ignoring "
737 			    "prefix with no valid time\n");
738 		return;
739 	}
740 
741 	if (debug & D_DHCP)
742 		logmsg(LOG_DEBUG, "incoming_prefix_stateful(%s, %s/%d)\n",
743 		    pi->pi_name, inet_ntop(AF_INET6,
744 		    (void *)&po->nd_opt_pi_prefix, abuf, sizeof (abuf)),
745 		    po->nd_opt_pi_prefix_len);
746 	foundpref = _B_FALSE;
747 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
748 		if (prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix,
749 		    po->nd_opt_pi_prefix_len)) {
750 			if ((pr->pr_flags & IFF_DHCPRUNNING) &&
751 			    pr->pr_prefix_len != po->nd_opt_pi_prefix_len) {
752 				pr->pr_prefix_len = po->nd_opt_pi_prefix_len;
753 				if (pr->pr_flags & IFF_UP) {
754 					if (debug & D_DHCP)
755 						logmsg(LOG_DEBUG,
756 						    "incoming_prefix_stateful:"
757 						    " set mask on DHCP %s\n",
758 						    pr->pr_name);
759 					prefix_update_dhcp(pr);
760 				}
761 			}
762 			if (pr->pr_prefix_len == po->nd_opt_pi_prefix_len &&
763 			    (!(pr->pr_state & PR_STATIC) ||
764 			    (pr->pr_flags & IFF_DHCPRUNNING)))
765 				foundpref = _B_TRUE;
766 		}
767 	}
768 	/*
769 	 * If there's no matching DHCPv6 prefix present, then create an empty
770 	 * one so that we'll be able to configure it later.
771 	 */
772 	if (!foundpref) {
773 		pr = prefix_create(pi, po->nd_opt_pi_prefix,
774 		    po->nd_opt_pi_prefix_len, IFF_DHCPRUNNING);
775 		if (pr != NULL) {
776 			pr->pr_state = PR_STATIC;
777 			if (debug & D_DHCP)
778 				logmsg(LOG_DEBUG,
779 				    "incoming_prefix_stateful: created dummy "
780 				    "prefix for later\n");
781 		}
782 	}
783 }
784 
785 /*
786  * Process prefix options with the autonomous flag set.
787  * Returns false if this prefix results in a bad address (duplicate)
788  * This function needs to loop to find the same prefix multiple times
789  * as if a failover happened earlier, the addresses belonging to
790  * a different interface may be found here on this interface.
791  */
792 static boolean_t
793 incoming_prefix_addrconf(struct phyint *pi, uchar_t *opt,
794     struct sockaddr_in6 *from, boolean_t loopback)
795 {
796 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
797 	int plen;
798 	struct prefix *pr;
799 	uint32_t validtime, preftime;	/* In seconds */
800 	char abuf[INET6_ADDRSTRLEN];
801 	char pbuf[INET6_ADDRSTRLEN];
802 	boolean_t found_pub = _B_FALSE;
803 	boolean_t found_tmp = _B_FALSE;
804 	boolean_t ret;
805 
806 	validtime = ntohl(po->nd_opt_pi_valid_time);
807 	preftime = ntohl(po->nd_opt_pi_preferred_time);
808 	plen = po->nd_opt_pi_prefix_len;
809 
810 	/* Sanity checks */
811 	if (validtime < preftime) {
812 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
813 		    abuf, sizeof (abuf));
814 		(void) inet_ntop(AF_INET6,
815 		    (void *)&po->nd_opt_pi_prefix,
816 		    pbuf, sizeof (pbuf));
817 		logmsg(LOG_WARNING, "prefix option %s/%u from %s on %s: "
818 		    "valid %u < pref %u ignored\n",
819 		    pbuf, plen, abuf, pi->pi_name,
820 		    validtime, preftime);
821 		return (_B_FALSE);
822 	}
823 
824 	for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
825 		if (pr->pr_prefix_len == plen &&
826 		    prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) {
827 
828 			/* Exclude static prefixes and DHCP */
829 			if ((pr->pr_state & PR_STATIC) ||
830 			    (pr->pr_flags & IFF_DHCPRUNNING))
831 				continue;
832 			if (pr->pr_flags & IFF_TEMPORARY) {
833 				/*
834 				 * If this address is deprecated and its token
835 				 * doesn't match the current tmp token, we want
836 				 * to create a new address with the current
837 				 * token.  So don't count this addr as a match.
838 				 */
839 				if (!((pr->pr_flags & IFF_DEPRECATED) &&
840 				    !token_equal(pi->pi_tmp_token,
841 				    pr->pr_address, TMP_TOKEN_BITS)))
842 					found_tmp = _B_TRUE;
843 			} else {
844 				found_pub = _B_TRUE;
845 			}
846 			(void) incoming_prefix_addrconf_process(pi, pr, opt,
847 			    from, loopback, _B_FALSE);
848 		}
849 	}
850 
851 	/*
852 	 * If we have found a matching prefix (for public and, if temp addrs
853 	 * are enabled, for temporary) already or validtime is zero, we have
854 	 * nothing to do.
855 	 */
856 	if (validtime == 0 ||
857 	    (found_pub && (!pi->pi_TmpAddrsEnabled || found_tmp)))
858 		return (_B_TRUE);
859 
860 	if (!found_pub) {
861 		pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0);
862 		if (pr == NULL)
863 			return (_B_TRUE);
864 		ret = incoming_prefix_addrconf_process(pi, pr, opt, from,
865 		    loopback, _B_TRUE);
866 	}
867 	/*
868 	 * if processing of the public address failed,
869 	 * don't bother with the temporary address.
870 	 */
871 	if (ret == _B_FALSE)
872 		return (_B_FALSE);
873 
874 	if (pi->pi_TmpAddrsEnabled && !found_tmp) {
875 		pr = prefix_create(pi, po->nd_opt_pi_prefix, plen,
876 		    IFF_TEMPORARY);
877 		if (pr == NULL)
878 			return (_B_TRUE);
879 		ret = incoming_prefix_addrconf_process(pi, pr, opt, from,
880 		    loopback, _B_TRUE);
881 	}
882 
883 	return (ret);
884 }
885 
886 boolean_t
887 incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr,
888     uchar_t *opt, struct sockaddr_in6 *from, boolean_t loopback,
889     boolean_t new_prefix)
890 {
891 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
892 	char abuf[INET6_ADDRSTRLEN];
893 	char pbuf[INET6_ADDRSTRLEN];
894 	uint32_t validtime, preftime;	/* In seconds */
895 	uint32_t recorded_validtime;	/* In seconds */
896 	int plen;
897 	struct prefix *other_pr;
898 
899 	validtime = ntohl(po->nd_opt_pi_valid_time);
900 	preftime = ntohl(po->nd_opt_pi_preferred_time);
901 	plen = po->nd_opt_pi_prefix_len;
902 	if (!new_prefix) {
903 		/*
904 		 * Check 2 hour rule on valid lifetime.
905 		 * Follows: RFC 2462
906 		 * If we advertised this prefix ourselves we skip
907 		 * these checks. They are also skipped if we did not
908 		 * previously do addrconf on this prefix.
909 		 */
910 		recorded_validtime = pr->pr_ValidLifetime / MILLISEC;
911 
912 		if (loopback || !(pr->pr_state & PR_AUTO) ||
913 		    validtime >= MIN_VALID_LIFETIME ||
914 		    /* LINTED - statement has no consequent */
915 		    validtime >= recorded_validtime) {
916 			/* OK */
917 		} else if (recorded_validtime < MIN_VALID_LIFETIME &&
918 		    validtime < recorded_validtime) {
919 			/* Ignore the prefix */
920 			(void) inet_ntop(AF_INET6,
921 			    (void *)&from->sin6_addr,
922 			    abuf, sizeof (abuf));
923 			(void) inet_ntop(AF_INET6,
924 			    (void *)&po->nd_opt_pi_prefix,
925 			    pbuf, sizeof (pbuf));
926 			logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: "
927 			    "too short valid lifetime %u stored %u "
928 			    "- ignored\n",
929 			    pbuf, plen, abuf, pi->pi_name,
930 			    validtime, recorded_validtime);
931 			return (_B_TRUE);
932 		} else {
933 			/*
934 			 * If the router clock runs slower than the
935 			 * host by 1 second over 2 hours then this
936 			 * test will set the lifetime back to 2 hours
937 			 * once i.e. a lifetime decrementing in
938 			 * realtime might cause the prefix to live an
939 			 * extra 2 hours on the host.
940 			 */
941 			(void) inet_ntop(AF_INET6,
942 			    (void *)&from->sin6_addr,
943 			    abuf, sizeof (abuf));
944 			(void) inet_ntop(AF_INET6,
945 			    (void *)&po->nd_opt_pi_prefix,
946 			    pbuf, sizeof (pbuf));
947 			logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: "
948 			    "valid time %u stored %u rounded up "
949 			    "to %u\n",
950 			    pbuf, plen, abuf, pi->pi_name,
951 			    validtime, recorded_validtime,
952 			    MIN_VALID_LIFETIME);
953 			validtime = MIN_VALID_LIFETIME;
954 		}
955 	}
956 
957 	/*
958 	 * For RFC3041 addresses, need to take token lifetime
959 	 * into account, too.
960 	 */
961 	if (pr->pr_flags & IFF_TEMPORARY) {
962 		uint_t	cur_tpreftime =
963 		    pi->pi_TmpPreferredLifetime - pi->pi_TmpDesyncFactor;
964 
965 		if (new_prefix) {
966 			validtime = MIN(validtime, pi->pi_TmpValidLifetime);
967 			preftime = MIN(preftime, cur_tpreftime);
968 		} else {
969 			uint_t cur_vexp, cur_pexp, curtime;
970 			curtime = getcurrenttime() / MILLISEC;
971 
972 			cur_vexp = pr->pr_CreateTime + pi->pi_TmpValidLifetime;
973 			cur_pexp = pr->pr_CreateTime + cur_tpreftime;
974 			if (curtime > cur_vexp)
975 				validtime = 0;
976 			else if ((curtime + validtime) > cur_vexp)
977 				validtime = cur_vexp - curtime;
978 			/*
979 			 * If this is an existing address which was deprecated
980 			 * because of a bad token, we don't want to update its
981 			 * preferred lifetime!
982 			 */
983 			if ((pr->pr_PreferredLifetime == 0) &&
984 			    !token_equal(pr->pr_address, pi->pi_tmp_token,
985 			    TMP_TOKEN_BITS))
986 				preftime = 0;
987 			else if (curtime > cur_pexp)
988 				preftime = 0;
989 			else if ((curtime + preftime) > cur_pexp)
990 				preftime = cur_pexp - curtime;
991 		}
992 		if ((preftime != 0) && (preftime <= pi->pi_TmpRegenAdvance)) {
993 			(void) inet_ntop(AF_INET6,
994 			    (void *)&from->sin6_addr,
995 			    abuf, sizeof (abuf));
996 			(void) inet_ntop(AF_INET6,
997 			    (void *)&po->nd_opt_pi_prefix,
998 			    pbuf, sizeof (pbuf));
999 			logmsg(LOG_WARNING, "prefix opt %s/%u from %s on %s: "
1000 			    "preferred lifetime(%d) <= TmpRegenAdvance(%d)\n",
1001 			    pbuf, plen, abuf, pi->pi_name, preftime,
1002 			    pi->pi_TmpRegenAdvance);
1003 			if (new_prefix) {
1004 				prefix_update_ipadm_addrobj(pr, _B_FALSE);
1005 				prefix_delete(pr);
1006 			}
1007 			return (_B_TRUE);
1008 		}
1009 	}
1010 	if (debug & D_TMP)
1011 		logmsg(LOG_DEBUG, "calculated lifetimes(%s, 0x%llx): v %d, "
1012 		    "p %d\n", pr->pr_name, pr->pr_flags, validtime, preftime);
1013 
1014 	if (!(pr->pr_state & PR_AUTO)) {
1015 		int i, tokenlen;
1016 		in6_addr_t *token;
1017 		/*
1018 		 * Form a new local address if the lengths match.
1019 		 */
1020 		if (pr->pr_flags & IFF_TEMPORARY) {
1021 			if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_tmp_token)) {
1022 				if (!tmptoken_create(pi)) {
1023 					prefix_delete(pr);
1024 					return (_B_TRUE);
1025 				}
1026 			}
1027 			tokenlen = TMP_TOKEN_BITS;
1028 			token = &pi->pi_tmp_token;
1029 		} else {
1030 			tokenlen = pi->pi_token_length;
1031 			token = &pi->pi_token;
1032 		}
1033 		if (pr->pr_prefix_len + tokenlen != IPV6_ABITS) {
1034 			(void) inet_ntop(AF_INET6,
1035 			    (void *)&from->sin6_addr,
1036 			    abuf, sizeof (abuf));
1037 			(void) inet_ntop(AF_INET6,
1038 			    (void *)&po->nd_opt_pi_prefix,
1039 			    pbuf, sizeof (pbuf));
1040 			logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: "
1041 			    "mismatched length %d token length %d\n",
1042 			    pbuf, plen, abuf, pi->pi_name,
1043 			    pr->pr_prefix_len, tokenlen);
1044 			return (_B_TRUE);
1045 		}
1046 		for (i = 0; i < 16; i++) {
1047 			/*
1048 			 * prefix_create ensures that pr_prefix has all-zero
1049 			 * bits after prefixlen.
1050 			 */
1051 			pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] |
1052 			    token->s6_addr[i];
1053 		}
1054 		/*
1055 		 * Check if any other physical interface has the same
1056 		 * address configured already
1057 		 */
1058 		if ((other_pr = prefix_lookup_addr_match(pr)) != NULL) {
1059 			/*
1060 			 * Delete this prefix structure as kernel
1061 			 * does not allow duplicated addresses
1062 			 */
1063 			logmsg(LOG_ERR, "incoming_prefix_addrconf_process: "
1064 			    "Duplicate prefix %s received on interface %s\n",
1065 			    inet_ntop(AF_INET6, &po->nd_opt_pi_prefix, abuf,
1066 			    sizeof (abuf)), pi->pi_name);
1067 			logmsg(LOG_ERR, "incoming_prefix_addrconf_process: "
1068 			    "Prefix already exists in interface %s\n",
1069 			    other_pr->pr_physical->pi_name);
1070 			if (new_prefix) {
1071 				prefix_update_ipadm_addrobj(pr, _B_FALSE);
1072 				prefix_delete(pr);
1073 				return (_B_FALSE);
1074 			}
1075 			/* Ignore for addrconf purposes */
1076 			validtime = preftime = 0;
1077 		}
1078 		if ((pr->pr_flags & IFF_TEMPORARY) && new_prefix) {
1079 			pr->pr_CreateTime = getcurrenttime() / MILLISEC;
1080 			if (debug & D_TMP)
1081 				logmsg(LOG_DEBUG,
1082 				    "created tmp addr(%s v %d p %d)\n",
1083 				    pr->pr_name, validtime, preftime);
1084 		}
1085 	}
1086 
1087 	if (validtime != 0)
1088 		pr->pr_state |= PR_AUTO;
1089 	else
1090 		pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED);
1091 	if (preftime != 0 || !(pr->pr_state & PR_AUTO))
1092 		pr->pr_state &= ~PR_DEPRECATED;
1093 	else
1094 		pr->pr_state |= PR_DEPRECATED;
1095 
1096 	/*
1097 	 * Convert from seconds to milliseconds avoiding overflow.
1098 	 * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1
1099 	 * (4 billion seconds - about 130 years) we will in fact time
1100 	 * out the prefix after 4 billion milliseconds - 46 days).
1101 	 * Thus the longest lifetime (apart from infinity) is 46 days.
1102 	 * Note that this ensures that PREFIX_INFINITY still means "forever".
1103 	 */
1104 	if (validtime >= PREFIX_INFINITY / MILLISEC)
1105 		pr->pr_ValidLifetime = PREFIX_INFINITY - 1;
1106 	else
1107 		pr->pr_ValidLifetime = validtime * MILLISEC;
1108 	if (preftime >= PREFIX_INFINITY / MILLISEC)
1109 		pr->pr_PreferredLifetime = PREFIX_INFINITY - 1;
1110 	else
1111 		pr->pr_PreferredLifetime = preftime * MILLISEC;
1112 	pr->pr_AutonomousFlag = _B_TRUE;
1113 
1114 	if (debug & D_PREFIX) {
1115 		logmsg(LOG_DEBUG, "incoming_prefix_addrconf_process(%s, %s/%u) "
1116 		    "valid %u pref %u\n",
1117 		    pr->pr_physical->pi_name,
1118 		    inet_ntop(AF_INET6, (void *)&pr->pr_prefix,
1119 		    abuf, sizeof (abuf)), pr->pr_prefix_len,
1120 		    pr->pr_ValidLifetime, pr->pr_PreferredLifetime);
1121 	}
1122 
1123 	if (pr->pr_state & PR_AUTO) {
1124 		/* Take the min of the two timeouts by calling it twice */
1125 		if (pr->pr_ValidLifetime != 0)
1126 			timer_schedule(pr->pr_ValidLifetime);
1127 		if (pr->pr_PreferredLifetime != 0)
1128 			timer_schedule(pr->pr_PreferredLifetime);
1129 	}
1130 	if (pr->pr_kernel_state != pr->pr_state) {
1131 		/* Log a message when an addrconf prefix goes away */
1132 		if ((pr->pr_kernel_state & PR_AUTO) &&
1133 		    !(pr->pr_state & PR_AUTO)) {
1134 			char abuf[INET6_ADDRSTRLEN];
1135 
1136 			logmsg(LOG_WARNING, "Address removed due to zero "
1137 			    "valid lifetime %s\n",
1138 			    inet_ntop(AF_INET6, (void *)&pr->pr_address,
1139 			    abuf, sizeof (abuf)));
1140 		}
1141 		prefix_update_k(pr);
1142 	}
1143 	return (_B_TRUE);
1144 }
1145 
1146 /*
1147  * Process an MTU option received in a router advertisement.
1148  */
1149 static void
1150 incoming_mtu_opt(struct phyint *pi, uchar_t *opt,
1151     struct sockaddr_in6 *from)
1152 {
1153 	struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt;
1154 	struct lifreq lifr;
1155 	uint32_t mtu;
1156 
1157 	if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) {
1158 		char abuf[INET6_ADDRSTRLEN];
1159 
1160 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1161 		    abuf, sizeof (abuf));
1162 		logmsg(LOG_INFO, "mtu option from %s on %s wrong size "
1163 		    "(%d bytes)\n",
1164 		    abuf, pi->pi_name,
1165 		    8 * (int)mo->nd_opt_mtu_len);
1166 		return;
1167 	}
1168 	mtu = ntohl(mo->nd_opt_mtu_mtu);
1169 	if (pi->pi_LinkMTU == mtu)
1170 		return;	/* No change */
1171 	if (mtu > pi->pi_mtu) {
1172 		/* Can't exceed physical MTU */
1173 		char abuf[INET6_ADDRSTRLEN];
1174 
1175 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1176 		    abuf, sizeof (abuf));
1177 		logmsg(LOG_INFO, "mtu option from %s on %s too large "
1178 		    "MTU %d - %d\n", abuf, pi->pi_name, mtu, pi->pi_mtu);
1179 		return;
1180 	}
1181 	if (mtu < IPV6_MIN_MTU) {
1182 		char abuf[INET6_ADDRSTRLEN];
1183 
1184 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1185 		    abuf, sizeof (abuf));
1186 		logmsg(LOG_INFO, "mtu option from %s on %s too small "
1187 		    "MTU (%d)\n", abuf, pi->pi_name, mtu);
1188 		return;
1189 	}
1190 
1191 	pi->pi_LinkMTU = mtu;
1192 	bzero(&lifr, sizeof (lifr));
1193 	(void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
1194 	lifr.lifr_ifinfo.lir_maxmtu = pi->pi_LinkMTU;
1195 	if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) {
1196 		logperror_pi(pi, "incoming_mtu_opt: SIOCSLIFLNKINFO");
1197 		return;
1198 	}
1199 }
1200 
1201 /*
1202  * Process a source link-layer address option received in a router
1203  * advertisement or solicitation.
1204  */
1205 static void
1206 incoming_lla_opt(struct phyint *pi, uchar_t *opt,
1207     struct sockaddr_in6 *from, int isrouter)
1208 {
1209 	struct nd_opt_lla *lo = (struct nd_opt_lla *)opt;
1210 	struct lifreq lifr;
1211 	struct sockaddr_in6 *sin6;
1212 	int max_content_len;
1213 
1214 	/*
1215 	 * Get our link-layer address length.  We may not have one, in which
1216 	 * case we can just bail.
1217 	 */
1218 	if (phyint_get_lla(pi, &lifr) != 0)
1219 		return;
1220 
1221 	/*
1222 	 * Can't remove padding since it is link type specific.
1223 	 * However, we check against the length of our link-layer address.
1224 	 * Note: assumes that all links have a fixed length address.
1225 	 */
1226 	max_content_len = lo->nd_opt_lla_len * 8 - sizeof (struct nd_opt_hdr);
1227 	if (max_content_len < lifr.lifr_nd.lnr_hdw_len ||
1228 	    (max_content_len >= 8 &&
1229 	    max_content_len - 7 > lifr.lifr_nd.lnr_hdw_len)) {
1230 		char abuf[INET6_ADDRSTRLEN];
1231 
1232 		(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1233 		    abuf, sizeof (abuf));
1234 		logmsg(LOG_INFO, "lla option from %s on %s too long with bad "
1235 		    "physaddr length (%d vs. %d bytes)\n", abuf, pi->pi_name,
1236 		    max_content_len, lifr.lifr_nd.lnr_hdw_len);
1237 		return;
1238 	}
1239 
1240 	bcopy(lo->nd_opt_lla_hdw_addr, lifr.lifr_nd.lnr_hdw_addr,
1241 	    lifr.lifr_nd.lnr_hdw_len);
1242 
1243 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr;
1244 	bzero(sin6, sizeof (struct sockaddr_in6));
1245 	sin6->sin6_family = AF_INET6;
1246 	sin6->sin6_addr = from->sin6_addr;
1247 
1248 	/*
1249 	 * Set IsRouter flag if RA; clear if RS.
1250 	 */
1251 	lifr.lifr_nd.lnr_state_create = ND_STALE;
1252 	lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED;
1253 	lifr.lifr_nd.lnr_state_diff_lla = ND_STALE;
1254 	lifr.lifr_nd.lnr_flags = isrouter;
1255 	(void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
1256 	if (ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr) < 0) {
1257 		logperror_pi(pi, "incoming_lla_opt: SIOCLIFSETND");
1258 		return;
1259 	}
1260 }
1261 
1262 /*
1263  * Verify the content of the received router advertisement against our
1264  * own configuration as specified in RFC 2461.
1265  */
1266 static void
1267 verify_ra_consistency(struct phyint *pi, struct nd_router_advert *ra, int len,
1268     struct sockaddr_in6 *from)
1269 {
1270 	char frombuf[INET6_ADDRSTRLEN];
1271 	struct nd_opt_hdr *opt;
1272 	int optlen;
1273 	uint_t reachable, retrans;
1274 	boolean_t pktflag, myflag;
1275 
1276 	(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1277 	    frombuf, sizeof (frombuf));
1278 
1279 	if (ra->nd_ra_curhoplimit != 0 &&
1280 	    pi->pi_AdvCurHopLimit != 0 &&
1281 	    ra->nd_ra_curhoplimit != pi->pi_AdvCurHopLimit) {
1282 		logmsg(LOG_INFO, "RA from %s on %s inconsistent cur hop "
1283 		    "limit:\n\treceived %d configuration %d\n",
1284 		    frombuf, pi->pi_name,
1285 		    ra->nd_ra_curhoplimit, pi->pi_AdvCurHopLimit);
1286 	}
1287 
1288 	reachable = ntohl(ra->nd_ra_reachable);
1289 	if (reachable != 0 && pi->pi_AdvReachableTime != 0 &&
1290 	    reachable != pi->pi_AdvReachableTime) {
1291 		logmsg(LOG_INFO, "RA from %s on %s inconsistent reachable "
1292 		    "time:\n\treceived %d configuration %d\n",
1293 		    frombuf, pi->pi_name,
1294 		    reachable, pi->pi_AdvReachableTime);
1295 	}
1296 
1297 	retrans = ntohl(ra->nd_ra_retransmit);
1298 	if (retrans != 0 && pi->pi_AdvRetransTimer != 0 &&
1299 	    retrans != pi->pi_AdvRetransTimer) {
1300 		logmsg(LOG_INFO, "RA from %s on %s inconsistent retransmit "
1301 		    "timer:\n\treceived %d configuration %d\n",
1302 		    frombuf, pi->pi_name,
1303 		    retrans, pi->pi_AdvRetransTimer);
1304 	}
1305 
1306 	pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != 0);
1307 	myflag = (pi->pi_AdvManagedFlag != 0);
1308 	if (pktflag != myflag) {
1309 		logmsg(LOG_INFO, "RA from %s on %s inconsistent managed "
1310 		    "flag:\n\treceived %s configuration %s\n",
1311 		    frombuf, pi->pi_name,
1312 		    (pktflag ? "ON" : "OFF"),
1313 		    (myflag ? "ON" : "OFF"));
1314 	}
1315 	pktflag = ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != 0);
1316 	myflag = (pi->pi_AdvOtherConfigFlag != 0);
1317 	if (pktflag != myflag) {
1318 		logmsg(LOG_INFO, "RA from %s on %s inconsistent other config "
1319 		    "flag:\n\treceived %s configuration %s\n",
1320 		    frombuf, pi->pi_name,
1321 		    (pktflag ? "ON" : "OFF"),
1322 		    (myflag ? "ON" : "OFF"));
1323 	}
1324 
1325 	/* Process any options */
1326 	len -= sizeof (struct nd_router_advert);
1327 	opt = (struct nd_opt_hdr *)&ra[1];
1328 	while (len >= sizeof (struct nd_opt_hdr)) {
1329 		optlen = opt->nd_opt_len * 8;
1330 		switch (opt->nd_opt_type) {
1331 		case ND_OPT_PREFIX_INFORMATION:
1332 			verify_prefix_opt(pi, (uchar_t *)opt, frombuf);
1333 			break;
1334 		case ND_OPT_MTU:
1335 			verify_mtu_opt(pi, (uchar_t *)opt, frombuf);
1336 			break;
1337 		default:
1338 			break;
1339 		}
1340 		opt = (struct nd_opt_hdr *)((char *)opt + optlen);
1341 		len -= optlen;
1342 	}
1343 }
1344 
1345 /*
1346  * Verify that the lifetimes and onlink/auto flags are consistent
1347  * with our settings.
1348  */
1349 static void
1350 verify_prefix_opt(struct phyint *pi, uchar_t *opt, char *frombuf)
1351 {
1352 	struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
1353 	int plen;
1354 	struct adv_prefix *adv_pr;
1355 	uint32_t validtime, preftime;
1356 	char prefixbuf[INET6_ADDRSTRLEN];
1357 	int pktflag, myflag;
1358 
1359 	if (8 * po->nd_opt_pi_len != sizeof (*po)) {
1360 		logmsg(LOG_INFO, "RA prefix option from %s on %s wrong size "
1361 		    "(%d bytes)\n",
1362 		    frombuf, pi->pi_name,
1363 		    8 * (int)po->nd_opt_pi_len);
1364 		return;
1365 	}
1366 	if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) {
1367 		logmsg(LOG_INFO, "RA from %s on %s contains link-local "
1368 		    "prefix - ignored\n",
1369 		    frombuf, pi->pi_name);
1370 		return;
1371 	}
1372 	plen = po->nd_opt_pi_prefix_len;
1373 	adv_pr = adv_prefix_lookup(pi, po->nd_opt_pi_prefix, plen);
1374 	if (adv_pr == NULL)
1375 		return;
1376 
1377 	/* Ignore prefixes which we do not advertise */
1378 	if (!adv_pr->adv_pr_AdvAutonomousFlag && !adv_pr->adv_pr_AdvOnLinkFlag)
1379 		return;
1380 	(void) inet_ntop(AF_INET6, (void *)&adv_pr->adv_pr_prefix,
1381 	    prefixbuf, sizeof (prefixbuf));
1382 	pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) != 0);
1383 	myflag = (adv_pr->adv_pr_AdvAutonomousFlag != 0);
1384 	if (pktflag != myflag) {
1385 		logmsg(LOG_INFO,
1386 		    "RA from %s on %s inconsistent autonomous flag for \n\t"
1387 		    "prefix %s/%u: received %s configuration %s\n",
1388 		    frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len,
1389 		    (pktflag ? "ON" : "OFF"),
1390 		    (myflag ? "ON" : "OFF"));
1391 	}
1392 
1393 	pktflag = ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) != 0);
1394 	myflag = (adv_pr->adv_pr_AdvOnLinkFlag != 0);
1395 	if (pktflag != myflag) {
1396 		logmsg(LOG_INFO, "RA from %s on %s inconsistent on link flag "
1397 		    "for \n\tprefix %s/%u: received %s configuration %s\n",
1398 		    frombuf, pi->pi_name, prefixbuf, adv_pr->adv_pr_prefix_len,
1399 		    (pktflag ? "ON" : "OFF"),
1400 		    (myflag ? "ON" : "OFF"));
1401 	}
1402 	validtime = ntohl(po->nd_opt_pi_valid_time);
1403 	preftime = ntohl(po->nd_opt_pi_preferred_time);
1404 
1405 	/*
1406 	 * Take into account variation for lifetimes decrementing
1407 	 * in real time. Allow +/- 10 percent and +/- 10 seconds.
1408 	 */
1409 #define	LOWER_LIMIT(val)	((val) - (val)/10 - 10)
1410 #define	UPPER_LIMIT(val)	((val) + (val)/10 + 10)
1411 	if (adv_pr->adv_pr_AdvValidRealTime) {
1412 		if (adv_pr->adv_pr_AdvValidExpiration > 0 &&
1413 		    (validtime <
1414 		    LOWER_LIMIT(adv_pr->adv_pr_AdvValidExpiration) ||
1415 		    validtime >
1416 		    UPPER_LIMIT(adv_pr->adv_pr_AdvValidExpiration))) {
1417 			logmsg(LOG_INFO, "RA from %s on %s inconsistent valid "
1418 			    "lifetime for\n\tprefix %s/%u: received %d "
1419 			    "configuration %d\n",
1420 			    frombuf, pi->pi_name, prefixbuf,
1421 			    adv_pr->adv_pr_prefix_len,
1422 			    validtime, adv_pr->adv_pr_AdvValidExpiration);
1423 		}
1424 	} else {
1425 		if (validtime != adv_pr->adv_pr_AdvValidLifetime) {
1426 			logmsg(LOG_INFO, "RA from %s on %s inconsistent valid "
1427 			    "lifetime for\n\tprefix %s/%u: received %d "
1428 			    "configuration %d\n",
1429 			    frombuf, pi->pi_name, prefixbuf,
1430 			    adv_pr->adv_pr_prefix_len,
1431 			    validtime, adv_pr->adv_pr_AdvValidLifetime);
1432 		}
1433 	}
1434 
1435 	if (adv_pr->adv_pr_AdvPreferredRealTime) {
1436 		if (adv_pr->adv_pr_AdvPreferredExpiration > 0 &&
1437 		    (preftime <
1438 		    LOWER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration) ||
1439 		    preftime >
1440 		    UPPER_LIMIT(adv_pr->adv_pr_AdvPreferredExpiration))) {
1441 			logmsg(LOG_INFO, "RA from %s on %s inconsistent "
1442 			    "preferred lifetime for\n\tprefix %s/%u: "
1443 			    "received %d configuration %d\n",
1444 			    frombuf, pi->pi_name, prefixbuf,
1445 			    adv_pr->adv_pr_prefix_len,
1446 			    preftime, adv_pr->adv_pr_AdvPreferredExpiration);
1447 		}
1448 	} else {
1449 		if (preftime != adv_pr->adv_pr_AdvPreferredLifetime) {
1450 			logmsg(LOG_INFO, "RA from %s on %s inconsistent "
1451 			    "preferred lifetime for\n\tprefix %s/%u: "
1452 			    "received %d configuration %d\n",
1453 			    frombuf, pi->pi_name, prefixbuf,
1454 			    adv_pr->adv_pr_prefix_len,
1455 			    preftime, adv_pr->adv_pr_AdvPreferredLifetime);
1456 		}
1457 	}
1458 }
1459 
1460 /*
1461  * Verify the received MTU against our own configuration.
1462  */
1463 static void
1464 verify_mtu_opt(struct phyint *pi, uchar_t *opt, char *frombuf)
1465 {
1466 	struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt;
1467 	uint32_t mtu;
1468 
1469 	if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) {
1470 		logmsg(LOG_INFO, "mtu option from %s on %s wrong size "
1471 		    "(%d bytes)\n",
1472 		    frombuf, pi->pi_name,
1473 		    8 * (int)mo->nd_opt_mtu_len);
1474 		return;
1475 	}
1476 	mtu = ntohl(mo->nd_opt_mtu_mtu);
1477 	if (pi->pi_AdvLinkMTU != 0 &&
1478 	    pi->pi_AdvLinkMTU != mtu) {
1479 		logmsg(LOG_INFO, "RA from %s on %s inconsistent MTU: "
1480 		    "received %d configuration %d\n",
1481 		    frombuf, pi->pi_name,
1482 		    mtu, pi->pi_AdvLinkMTU);
1483 	}
1484 }
1485 
1486 /*
1487  * Verify that all options have a non-zero length and that
1488  * the options fit within the total length of the packet (optlen).
1489  */
1490 static boolean_t
1491 verify_opt_len(struct nd_opt_hdr *opt, int optlen,
1492     struct phyint *pi, struct sockaddr_in6 *from)
1493 {
1494 	while (optlen > 0) {
1495 		if (opt->nd_opt_len == 0) {
1496 			char abuf[INET6_ADDRSTRLEN];
1497 
1498 			(void) inet_ntop(AF_INET6,
1499 			    (void *)&from->sin6_addr,
1500 			    abuf, sizeof (abuf));
1501 
1502 			logmsg(LOG_INFO, "Zero length option type 0x%x "
1503 			    "from %s on %s\n",
1504 			    opt->nd_opt_type, abuf, pi->pi_name);
1505 			return (_B_FALSE);
1506 		}
1507 		optlen -= 8 * opt->nd_opt_len;
1508 		if (optlen < 0) {
1509 			char abuf[INET6_ADDRSTRLEN];
1510 
1511 			(void) inet_ntop(AF_INET6,
1512 			    (void *)&from->sin6_addr,
1513 			    abuf, sizeof (abuf));
1514 
1515 			logmsg(LOG_INFO, "Too large option: type 0x%x len %u "
1516 			    "from %s on %s\n",
1517 			    opt->nd_opt_type, opt->nd_opt_len,
1518 			    abuf, pi->pi_name);
1519 			return (_B_FALSE);
1520 		}
1521 		opt = (struct nd_opt_hdr *)((char *)opt +
1522 		    8 * opt->nd_opt_len);
1523 	}
1524 	return (_B_TRUE);
1525 }
1526 
1527 /*
1528  * Update IsRouter Flag for Host turning into a router or vice-versa.
1529  */
1530 static void
1531 update_ra_flag(const struct phyint *pi, const struct sockaddr_in6 *from,
1532     int isrouter)
1533 {
1534 	struct lifreq lifr;
1535 	char abuf[INET6_ADDRSTRLEN];
1536 	struct sockaddr_in6 *sin6;
1537 
1538 	/* check if valid flag is being set */
1539 	if ((isrouter != NDF_ISROUTER_ON) &&
1540 	    (isrouter != NDF_ISROUTER_OFF)) {
1541 		logmsg(LOG_ERR, "update_ra_flag: Invalid IsRouter "
1542 		    "flag %d\n", isrouter);
1543 		return;
1544 	}
1545 
1546 	sin6 = (struct sockaddr_in6 *)&lifr.lifr_nd.lnr_addr;
1547 	bzero(sin6, sizeof (*sin6));
1548 	sin6->sin6_family = AF_INET6;
1549 	sin6->sin6_addr = from->sin6_addr;
1550 
1551 	(void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
1552 
1553 	if (ioctl(pi->pi_sock, SIOCLIFGETND, (char *)&lifr) < 0) {
1554 		if (errno == ESRCH) {
1555 			if (debug & D_IFSCAN) {
1556 				logmsg(LOG_DEBUG,
1557 "update_ra_flag: SIOCLIFGETND: nce doesn't exist, not setting IFF_ROUTER\n");
1558 			}
1559 		} else {
1560 			logperror_pi(pi, "update_ra_flag: SIOCLIFGETND");
1561 		}
1562 	} else {
1563 		/*
1564 		 * The lif_nd_req structure has three state values to be used
1565 		 * when changing/updating nces :
1566 		 * lnr_state_create, lnr_state_same_lla, and lnr_state_diff_lla.
1567 		 *
1568 		 * In this case, we're updating an nce, without changing lla;
1569 		 * so we set lnr_state_same_lla to ND_UNCHANGED, indicating that
1570 		 * nce's state should not be affected by our flag change.
1571 		 *
1572 		 * The kernel implementation also expects the lnr_state_create
1573 		 * field be always set, before processing ioctl request for NCE
1574 		 * update.
1575 		 * We use the state as STALE, while addressing the possibility
1576 		 * of NCE deletion when ioctl with SIOCLIFGETND argument
1577 		 * in earlier step is returned - further in such case we don't
1578 		 * want to re-create the entry in the reachable state.
1579 		 */
1580 		lifr.lifr_nd.lnr_state_create = ND_STALE;
1581 		lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED;
1582 		lifr.lifr_nd.lnr_flags = isrouter;
1583 		if ((ioctl(pi->pi_sock, SIOCLIFSETND, (char *)&lifr)) < 0) {
1584 			logperror_pi(pi, "update_ra_flag: SIOCLIFSETND");
1585 		} else {
1586 			(void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1587 			    abuf, sizeof (abuf));
1588 			logmsg(LOG_INFO, "update_ra_flag: IsRouter flag "
1589 			    "updated for %s\n", abuf);
1590 		}
1591 	}
1592 }
1593