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]
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.
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
,
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
,
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
,
70 static void verify_mtu_opt(struct phyint
*pi
, uchar_t
*opt
,
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.
81 find_ancillary(struct msghdr
*msg
, int cmsg_type
)
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
));
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];
105 char abuf
[INET6_ADDRSTRLEN
];
112 iov
.iov_base
= (char *)in_packet
;
113 iov
.iov_len
= sizeof (in_packet
);
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");
128 if (inet_ntop(AF_INET6
, (void *)&from
.sin6_addr
,
129 abuf
, sizeof (abuf
)) == NULL
)
130 msgbuf
= "Unspecified Router";
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
);
143 icmp
= (struct icmp6_hdr
*)in_packet
;
145 if (len
< ICMP6_MINLEN
) {
146 logmsg(LOG_INFO
, "Too short ICMP packet: %d bytes "
148 len
, msgbuf
, pi
->pi_name
);
152 opt
= find_ancillary(&msg
, IPV6_HOPLIMIT
);
154 /* Unknown hoplimit - must drop */
155 logmsg(LOG_INFO
, "Unknown hop limit from %s on %s\n",
156 msgbuf
, pi
->pi_name
);
159 hoplimit
= *(uint_t
*)opt
;
160 opt
= find_ancillary(&msg
, IPV6_RTHDR
);
162 /* Can't allow routing headers in ND messages */
163 logmsg(LOG_INFO
, "ND message with routing header "
165 msgbuf
, pi
->pi_name
);
168 switch (icmp
->icmp6_type
) {
169 case ND_ROUTER_SOLICIT
:
170 if (!pi
->pi_AdvSendAdvertisements
)
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",
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
);
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
);
197 if (len
< sizeof (struct nd_router_solicit
)) {
198 logmsg(LOG_INFO
, "RS too short: %d bytes "
200 len
, msgbuf
, pi
->pi_name
);
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
))
209 if (debug
& D_PKTIN
) {
210 print_route_sol("Received valid solicit from ", pi
,
213 incoming_rs(pi
, rs
, len
, &from
);
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.
223 "Router's address unspecified in advertisement\n");
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",
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
);
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
);
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
);
257 if (len
< sizeof (struct nd_router_advert
)) {
258 logmsg(LOG_INFO
, "RA too short: %d bytes "
260 len
, msgbuf
, pi
->pi_name
);
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
))
269 if (debug
& D_PKTIN
) {
270 print_route_adv("Received valid advert from ", pi
,
273 if (pi
->pi_AdvSendAdvertisements
)
274 verify_ra_consistency(pi
, ra
, len
, &from
);
276 incoming_ra(pi
, ra
, len
, &from
, _B_FALSE
);
282 * Process a received router solicitation.
283 * Check for source link-layer address option and check if it
284 * is time to advertise.
287 incoming_rs(struct phyint
*pi
, struct nd_router_solicit
*rs
, int len
,
288 struct sockaddr_in6
*from
)
290 struct nd_opt_hdr
*opt
;
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
);
306 opt
= (struct nd_opt_hdr
*)((char *)opt
+ 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
;
323 request
= dhcp_ipc_alloc_request(type
| DHCP_V6
, pi
->pi_name
, NULL
, 0,
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
) {
330 ~ND_RA_FLAG_MANAGED
& ~ND_RA_FLAG_OTHER
;
332 return (DHCP_IPC_E_MEMORY
);
335 error
= dhcp_ipc_make_request(request
, &reply
, 0);
338 logmsg(LOG_ERR
, "could not send request to dhcpagent: "
339 "%s: %s\n", pi
->pi_name
, dhcp_ipc_strerror(error
));
343 error
= reply
->return_code
;
350 * Start up DHCPv6 on a given physical interface. Does not wait for
351 * a message to be returned from the daemon.
354 start_dhcp(struct phyint
*pi
)
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
;
366 else if (pi
->pi_ra_flags
& ND_RA_FLAG_MANAGED
)
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.
388 release_dhcp(struct phyint
*pi
)
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.
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.
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
;
439 boolean_t set_needed
= _B_FALSE
;
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
)
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
++;
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
);
488 pi
->pi_RetransTimer
!= retrans
) {
489 pi
->pi_RetransTimer
= retrans
;
490 lifr
.lifr_ifinfo
.lir_reachretrans
= pi
->pi_RetransTimer
;
491 set_needed
= _B_TRUE
;
495 if (ioctl(pi
->pi_sock
, SIOCSLIFLNKINFO
, (char *)&lifr
) < 0) {
496 logperror_pi(pi
, "incoming_ra: SIOCSLIFLNKINFO");
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
) {
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",
525 pi
->pi_ra_flags
|= ra
->nd_ra_flags_reserved
;
529 /* Skip default router code if sent from ourselves */
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
);
535 if (router_lifetime
!= 0) {
536 dr
= router_create(pi
, from
->sin6_addr
,
537 MILLISEC
* router_lifetime
);
538 timer_schedule(dr
->dr_lifetime
);
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
))
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
,
560 incoming_mtu_opt(pi
, (uchar_t
*)opt
, from
);
562 case ND_OPT_SOURCE_LINKADDR
:
563 /* skip lla option if sent from ourselves! */
565 incoming_lla_opt(pi
, (uchar_t
*)opt
,
566 from
, NDF_ISROUTER_ON
);
567 slla_opt_present
= _B_TRUE
;
573 opt
= (struct nd_opt_hdr
*)((char *)opt
+ 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.
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 "
605 8 * (int)po
->nd_opt_pi_len
);
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 "
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
) &&
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
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.
642 incoming_prefix_onlink(struct phyint
*pi
, uchar_t
*opt
)
644 struct nd_opt_prefix_info
*po
= (struct nd_opt_prefix_info
*)opt
;
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
)
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
)
669 pr
= prefix_create(pi
, po
->nd_opt_pi_prefix
, plen
, 0);
672 incoming_prefix_onlink_process(pr
, opt
);
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
);
684 pr
->pr_state
|= PR_ONLINK
;
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
;
699 if (validtime
>= PREFIX_INFINITY
/ MILLISEC
)
700 pr
->pr_OnLinkLifetime
= PREFIX_INFINITY
- 1;
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
) {
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.
726 incoming_prefix_stateful(struct phyint
*pi
, uchar_t
*opt
)
728 struct nd_opt_prefix_info
*po
= (struct nd_opt_prefix_info
*)opt
;
731 char abuf
[INET6_ADDRSTRLEN
];
733 /* Make sure it's a valid prefix. */
734 if (ntohl(po
->nd_opt_pi_valid_time
) == 0) {
736 logmsg(LOG_DEBUG
, "incoming_prefix_stateful: ignoring "
737 "prefix with no valid time\n");
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
) {
756 "incoming_prefix_stateful:"
757 " set mask on DHCP %s\n",
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
)))
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.
773 pr
= prefix_create(pi
, po
->nd_opt_pi_prefix
,
774 po
->nd_opt_pi_prefix_len
, IFF_DHCPRUNNING
);
776 pr
->pr_state
= PR_STATIC
;
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.
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
;
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
;
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
;
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
);
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
))
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
)))
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
856 if (validtime
== 0 ||
857 (found_pub
&& (!pi
->pi_TmpAddrsEnabled
|| found_tmp
)))
861 pr
= prefix_create(pi
, po
->nd_opt_pi_prefix
, plen
, 0);
864 ret
= incoming_prefix_addrconf_process(pi
, pr
, opt
, from
,
868 * if processing of the public address failed,
869 * don't bother with the temporary address.
874 if (pi
->pi_TmpAddrsEnabled
&& !found_tmp
) {
875 pr
= prefix_create(pi
, po
->nd_opt_pi_prefix
, plen
,
879 ret
= incoming_prefix_addrconf_process(pi
, pr
, opt
, from
,
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 */
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
;
904 * Check 2 hour rule on valid lifetime.
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
) {
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 "
929 pbuf
, plen
, abuf
, pi
->pi_name
,
930 validtime
, recorded_validtime
);
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 "
950 pbuf
, plen
, abuf
, pi
->pi_name
,
951 validtime
, recorded_validtime
,
953 validtime
= MIN_VALID_LIFETIME
;
958 * For RFC3041 addresses, need to take token lifetime
961 if (pr
->pr_flags
& IFF_TEMPORARY
) {
962 uint_t cur_tpreftime
=
963 pi
->pi_TmpPreferredLifetime
- pi
->pi_TmpDesyncFactor
;
966 validtime
= MIN(validtime
, pi
->pi_TmpValidLifetime
);
967 preftime
= MIN(preftime
, cur_tpreftime
);
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
)
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
,
987 else if (curtime
> cur_pexp
)
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
);
1004 prefix_update_ipadm_addrobj(pr
, _B_FALSE
);
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
)) {
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
)) {
1027 tokenlen
= TMP_TOKEN_BITS
;
1028 token
= &pi
->pi_tmp_token
;
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
);
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
] |
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
);
1071 prefix_update_ipadm_addrobj(pr
, _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
;
1082 "created tmp addr(%s v %d p %d)\n",
1083 pr
->pr_name
, validtime
, preftime
);
1088 pr
->pr_state
|= PR_AUTO
;
1090 pr
->pr_state
&= ~(PR_AUTO
|PR_DEPRECATED
);
1091 if (preftime
!= 0 || !(pr
->pr_state
& PR_AUTO
))
1092 pr
->pr_state
&= ~PR_DEPRECATED
;
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;
1107 pr
->pr_ValidLifetime
= validtime
* MILLISEC
;
1108 if (preftime
>= PREFIX_INFINITY
/ MILLISEC
)
1109 pr
->pr_PreferredLifetime
= PREFIX_INFINITY
- 1;
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
);
1147 * Process an MTU option received in a router advertisement.
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
;
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 "
1165 8 * (int)mo
->nd_opt_mtu_len
);
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
);
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
);
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");
1202 * Process a source link-layer address option received in a router
1203 * advertisement or solicitation.
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
;
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)
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
);
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");
1263 * Verify the content of the received router advertisement against our
1264 * own configuration as specified in RFC 2461.
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
;
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
);
1335 verify_mtu_opt(pi
, (uchar_t
*)opt
, frombuf
);
1340 opt
= (struct nd_opt_hdr
*)((char *)opt
+ optlen
);
1346 * Verify that the lifetimes and onlink/auto flags are consistent
1347 * with our settings.
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
;
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 "
1362 frombuf
, pi
->pi_name
,
1363 8 * (int)po
->nd_opt_pi_len
);
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
);
1372 plen
= po
->nd_opt_pi_prefix_len
;
1373 adv_pr
= adv_prefix_lookup(pi
, po
->nd_opt_pi_prefix
, plen
);
1377 /* Ignore prefixes which we do not advertise */
1378 if (!adv_pr
->adv_pr_AdvAutonomousFlag
&& !adv_pr
->adv_pr_AdvOnLinkFlag
)
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
) {
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 &&
1414 LOWER_LIMIT(adv_pr
->adv_pr_AdvValidExpiration
) ||
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
);
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 &&
1438 LOWER_LIMIT(adv_pr
->adv_pr_AdvPreferredExpiration
) ||
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
);
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.
1464 verify_mtu_opt(struct phyint
*pi
, uchar_t
*opt
, char *frombuf
)
1466 struct nd_opt_mtu
*mo
= (struct nd_opt_mtu
*)opt
;
1469 if (8 * mo
->nd_opt_mtu_len
!= sizeof (*mo
)) {
1470 logmsg(LOG_INFO
, "mtu option from %s on %s wrong size "
1472 frombuf
, pi
->pi_name
,
1473 8 * (int)mo
->nd_opt_mtu_len
);
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).
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 "
1504 opt
->nd_opt_type
, abuf
, pi
->pi_name
);
1507 optlen
-= 8 * opt
->nd_opt_len
;
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 "
1517 opt
->nd_opt_type
, opt
->nd_opt_len
,
1521 opt
= (struct nd_opt_hdr
*)((char *)opt
+
1522 8 * opt
->nd_opt_len
);
1528 * Update IsRouter Flag for Host turning into a router or vice-versa.
1531 update_ra_flag(const struct phyint
*pi
, const struct sockaddr_in6
*from
,
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
);
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
) {
1557 "update_ra_flag: SIOCLIFGETND: nce doesn't exist, not setting IFF_ROUTER\n");
1560 logperror_pi(pi
, "update_ra_flag: SIOCLIFGETND");
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
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");
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
);