8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.lib / in.ndpd / ndp.c
blobe2a55bc0e01d9e8471d721db14189e5430333249
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
31 #include "defs.h"
32 #include "tables.h"
34 #include <sys/sysmacros.h>
36 #include <dhcpagent_ipc.h>
37 #include <dhcpagent_util.h>
39 static boolean_t verify_opt_len(struct nd_opt_hdr *opt, int optlen,
40 struct phyint *pi, struct sockaddr_in6 *from);
42 static void incoming_rs(struct phyint *pi, struct nd_router_solicit *rs,
43 int len, struct sockaddr_in6 *from);
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);
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);
73 static void update_ra_flag(const struct phyint *pi,
74 const struct sockaddr_in6 *from, int isrouter);
77 * Return a pointer to the specified option buffer.
78 * If not found return NULL.
80 static void *
81 find_ancillary(struct msghdr *msg, int cmsg_type)
83 struct cmsghdr *cmsg;
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));
92 return (NULL);
95 void
96 in_data(struct phyint *pi)
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;
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);
121 if ((len = recvmsg(pi->pi_sock, &msg, 0)) < 0) {
122 logperror_pi(pi, "in_data: recvfrom");
123 return;
125 if (len == 0)
126 return;
128 if (inet_ntop(AF_INET6, (void *)&from.sin6_addr,
129 abuf, sizeof (abuf)) == NULL)
130 msgbuf = "Unspecified Router";
131 else
132 msgbuf = abuf;
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);
140 return;
143 icmp = (struct icmp6_hdr *)in_packet;
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;
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;
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;
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);
178 return;
182 * Assumes that the kernel has verified the AH (if present)
183 * and the ICMP checksum.
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;
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;
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;
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;
209 if (debug & D_PKTIN) {
210 print_route_sol("Received valid solicit from ", pi,
211 rs, len, &from);
213 incoming_rs(pi, rs, len, &from);
214 break;
216 case ND_ROUTER_ADVERT:
217 if (IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr)) {
219 * Router advt. must have address!
220 * Logging the news and returning.
222 logmsg(LOG_DEBUG,
223 "Router's address unspecified in advertisement\n");
224 return;
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);
232 return;
236 * Assumes that the kernel has verified the AH (if present)
237 * and the ICMP checksum.
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;
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;
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;
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;
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;
269 if (debug & D_PKTIN) {
270 print_route_adv("Received valid advert from ", pi,
271 ra, len, &from);
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;
282 * Process a received router solicitation.
283 * Check for source link-layer address option and check if it
284 * is time to advertise.
286 static void
287 incoming_rs(struct phyint *pi, struct nd_router_solicit *rs, int len,
288 struct sockaddr_in6 *from)
290 struct nd_opt_hdr *opt;
291 int optlen;
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;
306 opt = (struct nd_opt_hdr *)((char *)opt + optlen);
307 len -= optlen;
309 /* Simple algorithm: treat unicast and multicast RSs the same */
310 check_to_advertise(pi, RECEIVED_SOLICIT);
314 * Function that sends commands to dhcpagent daemon.
317 dhcp_op(struct phyint *pi, int type)
319 dhcp_ipc_request_t *request;
320 dhcp_ipc_reply_t *reply = NULL;
321 int error;
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;
332 return (DHCP_IPC_E_MEMORY);
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);
343 error = reply->return_code;
344 free(reply);
346 return (error);
350 * Start up DHCPv6 on a given physical interface. Does not wait for
351 * a message to be returned from the daemon.
353 void
354 start_dhcp(struct phyint *pi)
356 int error;
357 int type;
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;
366 else if (pi->pi_ra_flags & ND_RA_FLAG_MANAGED)
367 type = DHCP_START;
368 else
369 type = DHCP_INFORM;
371 error = dhcp_op(pi, type);
373 * Timeout is considered to be "success" because we don't wait for DHCP
374 * to do its exchange.
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));
384 * Release the acquired DHCPv6 lease on a given physical interface.
385 * Does not wait for a message to be returned from the daemon.
387 void
388 release_dhcp(struct phyint *pi)
390 int error;
391 int type;
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) {
400 * Drop the dhcp control if we cannot release it.
402 type = DHCP_DROP;
403 goto retry;
405 logmsg(LOG_ERR, "Error in dhcpagent: %s: %s\n",
406 pi->pi_name, dhcp_ipc_strerror(error));
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.
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.
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;
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.
432 void
433 incoming_ra(struct phyint *pi, struct nd_router_advert *ra, int len,
434 struct sockaddr_in6 *from, boolean_t loopback)
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;
446 if (no_loopback && loopback)
447 return;
449 bzero(&lifr, sizeof (lifr));
450 (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
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;
458 if (pi->pi_CurHopLimit < bad_hopcount_threshhold) {
459 char abuf[INET6_ADDRSTRLEN];
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) : "");
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;
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;
484 lifr.lifr_ifinfo.lir_reachtime = pi->pi_ReachableTime;
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;
494 if (set_needed) {
495 if (ioctl(pi->pi_sock, SIOCSLIFLNKINFO, (char *)&lifr) < 0) {
496 logperror_pi(pi, "incoming_ra: SIOCSLIFLNKINFO");
497 return;
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.
506 if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
507 ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
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.
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);
525 pi->pi_ra_flags |= ra->nd_ra_flags_reserved;
526 start_dhcp(pi);
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);
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);
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;
569 break;
570 default:
571 break;
573 opt = (struct nd_opt_hdr *)((char *)opt + optlen);
574 len -= optlen;
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);
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.
587 * Note that when a flag (onlink or auto) is turned off we do nothing -
588 * the prefix will time out.
590 static void
591 incoming_prefix_opt(struct phyint *pi, uchar_t *opt,
592 struct sockaddr_in6 *from, boolean_t loopback)
594 struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt;
595 boolean_t good_prefix = _B_TRUE;
597 if (8 * po->nd_opt_pi_len != sizeof (*po)) {
598 char abuf[INET6_ADDRSTRLEN];
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;
608 if (IN6_IS_ADDR_LINKLOCAL(&po->nd_opt_pi_prefix)) {
609 char abuf[INET6_ADDRSTRLEN];
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;
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);
622 if ((po->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) &&
623 good_prefix) {
624 incoming_prefix_onlink(pi, opt);
626 if (pi->pi_stateful && pi->pi_autoconf)
627 incoming_prefix_stateful(pi, opt);
631 * Process prefix options with the onlink flag set.
633 * If there are no routers ndpd will add an onlink
634 * default route which will allow communication
635 * between neighbors.
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.
641 static void
642 incoming_prefix_onlink(struct phyint *pi, uchar_t *opt)
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;
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);
662 validtime = ntohl(po->nd_opt_pi_valid_time);
664 * If we have found a matching prefix already or validtime
665 * is zero, we have nothing to do.
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);
675 void
676 incoming_prefix_onlink_process(struct prefix *pr, uchar_t *opt)
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];
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;
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".
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;
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);
713 if (pr->pr_kernel_state != pr->pr_state) {
714 prefix_update_k(pr);
717 if (pr->pr_OnLinkLifetime != 0)
718 timer_schedule(pr->pr_OnLinkLifetime);
722 * Process all prefix options by locating the DHCPv6-configured interfaces, and
723 * applying the netmasks as needed.
725 static void
726 incoming_prefix_stateful(struct phyint *pi, uchar_t *opt)
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];
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;
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);
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;
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.
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");
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.
792 static boolean_t
793 incoming_prefix_addrconf(struct phyint *pi, uchar_t *opt,
794 struct sockaddr_in6 *from, boolean_t loopback)
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;
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;
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);
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)) {
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) {
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.
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;
846 (void) incoming_prefix_addrconf_process(pi, pr, opt,
847 from, loopback, _B_FALSE);
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.
856 if (validtime == 0 ||
857 (found_pub && (!pi->pi_TmpAddrsEnabled || found_tmp)))
858 return (_B_TRUE);
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);
868 * if processing of the public address failed,
869 * don't bother with the temporary address.
871 if (ret == _B_FALSE)
872 return (_B_FALSE);
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);
883 return (ret);
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)
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;
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) {
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.
910 recorded_validtime = pr->pr_ValidLifetime / MILLISEC;
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 {
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.
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;
958 * For RFC3041 addresses, need to take token lifetime
959 * into account, too.
961 if (pr->pr_flags & IFF_TEMPORARY) {
962 uint_t cur_tpreftime =
963 pi->pi_TmpPreferredLifetime - pi->pi_TmpDesyncFactor;
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;
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;
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!
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;
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);
1007 return (_B_TRUE);
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);
1014 if (!(pr->pr_state & PR_AUTO)) {
1015 int i, tokenlen;
1016 in6_addr_t *token;
1018 * Form a new local address if the lengths match.
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);
1027 tokenlen = TMP_TOKEN_BITS;
1028 token = &pi->pi_tmp_token;
1029 } else {
1030 tokenlen = pi->pi_token_length;
1031 token = &pi->pi_token;
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);
1046 for (i = 0; i < 16; i++) {
1048 * prefix_create ensures that pr_prefix has all-zero
1049 * bits after prefixlen.
1051 pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] |
1052 token->s6_addr[i];
1055 * Check if any other physical interface has the same
1056 * address configured already
1058 if ((other_pr = prefix_lookup_addr_match(pr)) != NULL) {
1060 * Delete this prefix structure as kernel
1061 * does not allow duplicated addresses
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);
1075 /* Ignore for addrconf purposes */
1076 validtime = preftime = 0;
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);
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;
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".
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;
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);
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);
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];
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)));
1141 prefix_update_k(pr);
1143 return (_B_TRUE);
1147 * Process an MTU option received in a router advertisement.
1149 static void
1150 incoming_mtu_opt(struct phyint *pi, uchar_t *opt,
1151 struct sockaddr_in6 *from)
1153 struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt;
1154 struct lifreq lifr;
1155 uint32_t mtu;
1157 if (8 * mo->nd_opt_mtu_len != sizeof (*mo)) {
1158 char abuf[INET6_ADDRSTRLEN];
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;
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];
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;
1181 if (mtu < IPV6_MIN_MTU) {
1182 char abuf[INET6_ADDRSTRLEN];
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;
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;
1202 * Process a source link-layer address option received in a router
1203 * advertisement or solicitation.
1205 static void
1206 incoming_lla_opt(struct phyint *pi, uchar_t *opt,
1207 struct sockaddr_in6 *from, int isrouter)
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;
1215 * Get our link-layer address length. We may not have one, in which
1216 * case we can just bail.
1218 if (phyint_get_lla(pi, &lifr) != 0)
1219 return;
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.
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];
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;
1240 bcopy(lo->nd_opt_lla_hdw_addr, lifr.lifr_nd.lnr_hdw_addr,
1241 lifr.lifr_nd.lnr_hdw_len);
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;
1249 * Set IsRouter flag if RA; clear if RS.
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;
1263 * Verify the content of the received router advertisement against our
1264 * own configuration as specified in RFC 2461.
1266 static void
1267 verify_ra_consistency(struct phyint *pi, struct nd_router_advert *ra, int len,
1268 struct sockaddr_in6 *from)
1270 char frombuf[INET6_ADDRSTRLEN];
1271 struct nd_opt_hdr *opt;
1272 int optlen;
1273 uint_t reachable, retrans;
1274 boolean_t pktflag, myflag;
1276 (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr,
1277 frombuf, sizeof (frombuf));
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);
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);
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);
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"));
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"));
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;
1340 opt = (struct nd_opt_hdr *)((char *)opt + optlen);
1341 len -= optlen;
1346 * Verify that the lifetimes and onlink/auto flags are consistent
1347 * with our settings.
1349 static void
1350 verify_prefix_opt(struct phyint *pi, uchar_t *opt, char *frombuf)
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;
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;
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;
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;
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"));
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"));
1402 validtime = ntohl(po->nd_opt_pi_valid_time);
1403 preftime = ntohl(po->nd_opt_pi_preferred_time);
1406 * Take into account variation for lifetimes decrementing
1407 * in real time. Allow +/- 10 percent and +/- 10 seconds.
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);
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);
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);
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);
1461 * Verify the received MTU against our own configuration.
1463 static void
1464 verify_mtu_opt(struct phyint *pi, uchar_t *opt, char *frombuf)
1466 struct nd_opt_mtu *mo = (struct nd_opt_mtu *)opt;
1467 uint32_t mtu;
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;
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);
1487 * Verify that all options have a non-zero length and that
1488 * the options fit within the total length of the packet (optlen).
1490 static boolean_t
1491 verify_opt_len(struct nd_opt_hdr *opt, int optlen,
1492 struct phyint *pi, struct sockaddr_in6 *from)
1494 while (optlen > 0) {
1495 if (opt->nd_opt_len == 0) {
1496 char abuf[INET6_ADDRSTRLEN];
1498 (void) inet_ntop(AF_INET6,
1499 (void *)&from->sin6_addr,
1500 abuf, sizeof (abuf));
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);
1507 optlen -= 8 * opt->nd_opt_len;
1508 if (optlen < 0) {
1509 char abuf[INET6_ADDRSTRLEN];
1511 (void) inet_ntop(AF_INET6,
1512 (void *)&from->sin6_addr,
1513 abuf, sizeof (abuf));
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);
1521 opt = (struct nd_opt_hdr *)((char *)opt +
1522 8 * opt->nd_opt_len);
1524 return (_B_TRUE);
1528 * Update IsRouter Flag for Host turning into a router or vice-versa.
1530 static void
1531 update_ra_flag(const struct phyint *pi, const struct sockaddr_in6 *from,
1532 int isrouter)
1534 struct lifreq lifr;
1535 char abuf[INET6_ADDRSTRLEN];
1536 struct sockaddr_in6 *sin6;
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;
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;
1551 (void) strlcpy(lifr.lifr_name, pi->pi_name, sizeof (lifr.lifr_name));
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");
1559 } else {
1560 logperror_pi(pi, "update_ra_flag: SIOCLIFGETND");
1562 } else {
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.
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.
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.
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);