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]
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
32 struct phyint
*phyints
= NULL
;
33 int num_of_phyints
= 0;
35 static void phyint_print(struct phyint
*pi
);
36 static void phyint_insert(struct phyint
*pi
);
38 static boolean_t
tmptoken_isvalid(struct in6_addr
*token
);
40 static void prefix_print(struct prefix
*pr
);
41 static void prefix_insert(struct phyint
*pi
, struct prefix
*pr
);
42 static char *prefix_print_state(int state
, char *buf
, int buflen
);
43 static void prefix_set(struct in6_addr
*prefix
, struct in6_addr addr
,
46 static void adv_prefix_print(struct adv_prefix
*adv_pr
);
47 static void adv_prefix_insert(struct phyint
*pi
, struct adv_prefix
*adv_pr
);
48 static void adv_prefix_delete(struct adv_prefix
*adv_pr
);
50 static void router_print(struct router
*dr
);
51 static void router_insert(struct phyint
*pi
, struct router
*dr
);
52 static void router_delete(struct router
*dr
);
53 static void router_add_k(struct router
*dr
);
54 static void router_delete_k(struct router
*dr
);
56 static int rtmseq
; /* rtm_seq sequence number */
59 #define NDP_PREFIX_DEFAULT_LIFETIME (7*24*60*60*1000)
61 phyint_lookup(char *name
)
66 logmsg(LOG_DEBUG
, "phyint_lookup(%s)\n", name
);
68 for (pi
= phyints
; pi
!= NULL
; pi
= pi
->pi_next
) {
69 if (strcmp(pi
->pi_name
, name
) == 0)
76 phyint_lookup_on_index(uint_t ifindex
)
81 logmsg(LOG_DEBUG
, "phyint_lookup_on_index(%d)\n", ifindex
);
83 for (pi
= phyints
; pi
!= NULL
; pi
= pi
->pi_next
) {
84 if (pi
->pi_index
== ifindex
)
91 phyint_create(char *name
)
97 logmsg(LOG_DEBUG
, "phyint_create(%s)\n", name
);
99 pi
= (struct phyint
*)calloc(sizeof (struct phyint
), 1);
101 logmsg(LOG_ERR
, "phyint_create: out of memory\n");
104 (void) strncpy(pi
->pi_name
, name
, sizeof (pi
->pi_name
));
105 pi
->pi_name
[sizeof (pi
->pi_name
) - 1] = '\0';
108 * Copy the defaults from the defaults array.
109 * Do not copy the cf_notdefault fields since these have not
110 * been explicitly set for the phyint.
112 for (i
= 0; i
< I_IFSIZE
; i
++)
113 pi
->pi_config
[i
].cf_value
= ifdefaults
[i
].cf_value
;
116 * TmpDesyncFactor is used to desynchronize temporary token
117 * generation among systems; the actual preferred lifetime value
118 * of a temporary address will be (TmpPreferredLifetime -
119 * TmpDesyncFactor). It's a random value, with a user-configurable
120 * maximum value. The value is constant throughout the lifetime
121 * of the in.ndpd process, but can change if the daemon is restarted,
124 if (pi
->pi_TmpMaxDesyncFactor
!= 0) {
125 time_t seed
= time(NULL
);
127 pi
->pi_TmpDesyncFactor
= rand() % pi
->pi_TmpMaxDesyncFactor
;
128 /* we actually want [1,max], not [0,(max-1)] */
129 pi
->pi_TmpDesyncFactor
++;
131 pi
->pi_TmpRegenCountdown
= TIMER_INFINITY
;
134 pi
->pi_stateless
= pi
->pi_StatelessAddrConf
;
135 pi
->pi_stateful
= pi
->pi_StatefulAddrConf
;
136 pi
->pi_autoconf
= _B_TRUE
;
137 pi
->pi_default_token
= _B_TRUE
;
138 if (phyint_init_from_k(pi
) == -1) {
143 if (pi
->pi_sock
!= -1) {
144 if (poll_add(pi
->pi_sock
) == -1) {
152 /* Insert in linked list */
154 phyint_insert(struct phyint
*pi
)
157 pi
->pi_next
= phyints
;
160 phyints
->pi_prev
= pi
;
166 * Initialize both the phyint data structure and the pi_sock for
167 * sending and receving on the interface.
168 * Extract information from the kernel (if present) and set pi_kernel_state.
171 phyint_init_from_k(struct phyint
*pi
)
173 struct ipv6_mreq v6mcastr
;
179 struct sockaddr_in6
*sin6
;
181 if (debug
& D_PHYINT
)
182 logmsg(LOG_DEBUG
, "phyint_init_from_k(%s)\n", pi
->pi_name
);
186 if (pi
->pi_sock
< 0) {
187 pi
->pi_sock
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
188 if (pi
->pi_sock
< 0) {
189 logperror_pi(pi
, "phyint_init_from_k: socket");
198 (void) strncpy(lifr
.lifr_name
, pi
->pi_name
, sizeof (lifr
.lifr_name
));
199 lifr
.lifr_name
[sizeof (lifr
.lifr_name
) - 1] = '\0';
200 if (ioctl(fd
, SIOCGLIFINDEX
, (char *)&lifr
) < 0) {
201 if (errno
== ENXIO
) {
203 (void) close(pi
->pi_sock
);
206 if (debug
& D_PHYINT
) {
207 logmsg(LOG_DEBUG
, "phyint_init_from_k(%s): "
208 "not exist\n", pi
->pi_name
);
212 logperror_pi(pi
, "phyint_init_from_k: SIOCGLIFINDEX");
216 if (!newsock
&& (pi
->pi_index
!= lifr
.lifr_index
)) {
218 * Interface has been re-plumbed, lets open a new socket.
219 * This situation can occur if plumb/unplumb are happening
227 pi
->pi_index
= lifr
.lifr_index
;
229 if (ioctl(fd
, SIOCGLIFFLAGS
, (char *)&lifr
) < 0) {
230 logperror_pi(pi
, "phyint_init_from_k: ioctl (get flags)");
233 pi
->pi_flags
= lifr
.lifr_flags
;
236 * If the link local interface is not up yet or it's IFF_UP and the
237 * IFF_NOLOCAL flag is set, then ignore the interface.
239 if (!(pi
->pi_flags
& IFF_UP
) || (pi
->pi_flags
& IFF_NOLOCAL
)) {
241 (void) close(pi
->pi_sock
);
245 if (debug
& D_PHYINT
) {
246 logmsg(LOG_DEBUG
, "phyint_init_from_k(%s): "
247 "IFF_NOLOCAL or not IFF_UP\n", pi
->pi_name
);
251 pi
->pi_kernel_state
|= PI_PRESENT
;
253 if (ioctl(fd
, SIOCGLIFMTU
, (caddr_t
)&lifr
) < 0) {
254 logperror_pi(pi
, "phyint_init_from_k: ioctl (get mtu)");
257 pi
->pi_mtu
= lifr
.lifr_mtu
;
259 if (ioctl(fd
, SIOCGLIFADDR
, (char *)&lifr
) < 0) {
260 logperror_pi(pi
, "phyint_init_from_k: SIOCGLIFADDR");
263 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
264 pi
->pi_ifaddr
= sin6
->sin6_addr
;
266 if (pi
->pi_autoconf
&& pi
->pi_default_token
) {
267 if (ioctl(fd
, SIOCGLIFTOKEN
, (char *)&lifr
) < 0) {
268 logperror_pi(pi
, "phyint_init_from_k: SIOCGLIFTOKEN");
271 /* Ignore interface if the token is all zeros */
272 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_token
;
273 if (IN6_IS_ADDR_UNSPECIFIED(&sin6
->sin6_addr
)) {
274 logmsg(LOG_ERR
, "ignoring interface %s: zero token\n",
278 pi
->pi_token
= sin6
->sin6_addr
;
279 pi
->pi_token_length
= lifr
.lifr_addrlen
;
283 * Guess a remote token for POINTOPOINT by looking at
284 * the link-local destination address.
286 if (pi
->pi_flags
& IFF_POINTOPOINT
) {
287 if (ioctl(fd
, SIOCGLIFDSTADDR
, (char *)&lifr
) < 0) {
288 logperror_pi(pi
, "phyint_init_from_k: SIOCGLIFDSTADDR");
291 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
292 if (sin6
->sin6_family
!= AF_INET6
||
293 IN6_IS_ADDR_UNSPECIFIED(&sin6
->sin6_addr
) ||
294 !IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
)) {
295 pi
->pi_dst_token
= in6addr_any
;
297 pi
->pi_dst_token
= sin6
->sin6_addr
;
298 /* Clear link-local prefix (first 10 bits) */
299 pi
->pi_dst_token
.s6_addr
[0] = 0;
300 pi
->pi_dst_token
.s6_addr
[1] &= 0x3f;
303 pi
->pi_dst_token
= in6addr_any
;
307 icmp6_filter_t filter
;
310 /* Set default values */
311 pi
->pi_LinkMTU
= pi
->pi_mtu
;
312 pi
->pi_CurHopLimit
= 0;
313 pi
->pi_BaseReachableTime
= ND_REACHABLE_TIME
;
314 phyint_reach_random(pi
, _B_FALSE
);
315 pi
->pi_RetransTimer
= ND_RETRANS_TIMER
;
317 /* Setup socket for transmission and reception */
318 if (setsockopt(fd
, IPPROTO_IPV6
,
319 IPV6_BOUND_IF
, (char *)&pi
->pi_index
,
320 sizeof (pi
->pi_index
)) < 0) {
321 logperror_pi(pi
, "phyint_init_from_k: setsockopt "
327 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
,
328 (char *)&ttl
, sizeof (ttl
)) < 0) {
329 logperror_pi(pi
, "phyint_init_from_k: setsockopt "
330 "IPV6_UNICAST_HOPS");
334 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
,
335 (char *)&ttl
, sizeof (ttl
)) < 0) {
336 logperror_pi(pi
, "phyint_init_from_k: setsockopt "
337 "IPV6_MULTICAST_HOPS");
341 v6mcastr
.ipv6mr_multiaddr
= all_nodes_mcast
;
342 v6mcastr
.ipv6mr_interface
= pi
->pi_index
;
343 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
,
344 (char *)&v6mcastr
, sizeof (v6mcastr
)) < 0) {
346 * One benign reason IPV6_JOIN_GROUP could fail is
347 * when `pi' has been placed into an IPMP group and we
348 * haven't yet processed the routing socket message
349 * informing us of its disappearance. As such, if
350 * it's now in a group, don't print an error.
353 (void) strlcpy(lifr
.lifr_name
, pi
->pi_name
, LIFNAMSIZ
);
354 if (ioctl(fd
, SIOCGLIFGROUPNAME
, &lifr
) == -1 ||
355 lifr
.lifr_groupname
[0] == '\0') {
357 logperror_pi(pi
, "phyint_init_from_k: "
358 "setsockopt IPV6_JOIN_GROUP");
362 pi
->pi_state
|= PI_JOINED_ALLNODES
;
363 pi
->pi_kernel_state
|= PI_JOINED_ALLNODES
;
366 * Filter out so that we only receive router advertisements and
367 * router solicitations.
369 ICMP6_FILTER_SETBLOCKALL(&filter
);
370 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT
, &filter
);
371 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT
, &filter
);
373 if (setsockopt(fd
, IPPROTO_ICMPV6
, ICMP6_FILTER
,
374 (char *)&filter
, sizeof (filter
)) < 0) {
375 logperror_pi(pi
, "phyint_init_from_k: setsockopt "
380 /* Enable receipt of ancillary data */
381 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
,
382 (char *)&on
, sizeof (on
)) < 0) {
383 logperror_pi(pi
, "phyint_init_from_k: setsockopt "
384 "IPV6_RECVHOPLIMIT");
387 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVRTHDR
,
388 (char *)&on
, sizeof (on
)) < 0) {
389 logperror_pi(pi
, "phyint_init_from_k: setsockopt "
395 if (pi
->pi_AdvSendAdvertisements
&&
396 !(pi
->pi_kernel_state
& PI_JOINED_ALLROUTERS
)) {
397 v6mcastr
.ipv6mr_multiaddr
= all_routers_mcast
;
398 v6mcastr
.ipv6mr_interface
= pi
->pi_index
;
399 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
,
400 (char *)&v6mcastr
, sizeof (v6mcastr
)) < 0) {
402 * See IPV6_JOIN_GROUP comment above.
405 (void) strlcpy(lifr
.lifr_name
, pi
->pi_name
, LIFNAMSIZ
);
406 if (ioctl(fd
, SIOCGLIFGROUPNAME
, &lifr
) == -1 ||
407 lifr
.lifr_groupname
[0] == '\0') {
409 logperror_pi(pi
, "phyint_init_from_k: "
410 "setsockopt IPV6_JOIN_GROUP");
414 pi
->pi_state
|= PI_JOINED_ALLROUTERS
;
415 pi
->pi_kernel_state
|= PI_JOINED_ALLROUTERS
;
418 * If not already set, set the IFF_ROUTER interface flag based on
419 * AdvSendAdvertisements. Note that this will also enable IPv6
420 * forwarding on the interface. We don't clear IFF_ROUTER if we're
421 * not advertising on an interface, because we could still be
422 * forwarding on those interfaces.
424 (void) strncpy(lifr
.lifr_name
, pi
->pi_name
, sizeof (lifr
.lifr_name
));
425 lifr
.lifr_name
[sizeof (lifr
.lifr_name
) - 1] = '\0';
426 if (ioctl(fd
, SIOCGLIFFLAGS
, (char *)&lifr
) < 0) {
427 logperror_pi(pi
, "phyint_init_from_k: SIOCGLIFFLAGS");
430 if (!(lifr
.lifr_flags
& IFF_ROUTER
) && pi
->pi_AdvSendAdvertisements
) {
431 lifr
.lifr_flags
|= IFF_ROUTER
;
433 if (ioctl(fd
, SIOCSLIFFLAGS
, (char *)&lifr
) < 0) {
434 logperror_pi(pi
, "phyint_init_from_k: SIOCSLIFFLAGS");
437 pi
->pi_flags
= lifr
.lifr_flags
;
440 /* Set linkinfo parameters */
441 (void) strncpy(lifr
.lifr_name
, pi
->pi_name
, sizeof (lifr
.lifr_name
));
442 lifr
.lifr_name
[sizeof (lifr
.lifr_name
) - 1] = '\0';
443 lifr
.lifr_ifinfo
.lir_maxhops
= pi
->pi_CurHopLimit
;
444 lifr
.lifr_ifinfo
.lir_reachtime
= pi
->pi_ReachableTime
;
445 lifr
.lifr_ifinfo
.lir_reachretrans
= pi
->pi_RetransTimer
;
446 /* Setting maxmtu to 0 means that we're leaving the MTU alone */
447 lifr
.lifr_ifinfo
.lir_maxmtu
= 0;
448 if (ioctl(fd
, SIOCSLIFLNKINFO
, (char *)&lifr
) < 0) {
449 logperror_pi(pi
, "phyint_init_from_k: SIOCSLIFLNKINFO");
452 if (debug
& D_PHYINT
) {
453 logmsg(LOG_DEBUG
, "phyint_init_from_k(%s): done\n",
459 /* Pretend the interface does not exist in the kernel */
460 pi
->pi_kernel_state
&= ~PI_PRESENT
;
462 (void) close(pi
->pi_sock
);
469 * Delete (unlink and free).
470 * Handles delete of things that have not yet been inserted in the list.
473 phyint_delete(struct phyint
*pi
)
475 if (debug
& D_PHYINT
)
476 logmsg(LOG_DEBUG
, "phyint_delete(%s)\n", pi
->pi_name
);
478 assert(num_of_phyints
> 0);
480 while (pi
->pi_router_list
)
481 router_delete(pi
->pi_router_list
);
482 while (pi
->pi_prefix_list
) {
483 prefix_update_ipadm_addrobj(pi
->pi_prefix_list
, _B_FALSE
);
484 prefix_delete(pi
->pi_prefix_list
);
486 while (pi
->pi_adv_prefix_list
)
487 adv_prefix_delete(pi
->pi_adv_prefix_list
);
489 if (pi
->pi_sock
!= -1) {
490 (void) poll_remove(pi
->pi_sock
);
491 if (close(pi
->pi_sock
) < 0) {
492 logperror_pi(pi
, "phyint_delete: close");
497 if (pi
->pi_prev
== NULL
) {
499 phyints
= pi
->pi_next
;
501 pi
->pi_prev
->pi_next
= pi
->pi_next
;
503 if (pi
->pi_next
!= NULL
)
504 pi
->pi_next
->pi_prev
= pi
->pi_prev
;
505 pi
->pi_next
= pi
->pi_prev
= NULL
;
511 * Called with the number of milliseconds elapsed since the last call.
512 * Determines if any timeout event has occurred and
513 * returns the number of milliseconds until the next timeout event
514 * for the phyint itself (excluding prefixes and routers).
515 * Returns TIMER_INFINITY for "never".
518 phyint_timer(struct phyint
*pi
, uint_t elapsed
)
520 uint_t next
= TIMER_INFINITY
;
522 if (pi
->pi_AdvSendAdvertisements
) {
523 if (pi
->pi_adv_state
!= NO_ADV
) {
524 int old_state
= pi
->pi_adv_state
;
526 if (debug
& (D_STATE
|D_PHYINT
)) {
527 logmsg(LOG_DEBUG
, "phyint_timer ADV(%s) "
528 "state %d\n", pi
->pi_name
, (int)old_state
);
530 next
= advertise_event(pi
, ADV_TIMER
, elapsed
);
531 if (debug
& D_STATE
) {
532 logmsg(LOG_DEBUG
, "phyint_timer ADV(%s) "
534 pi
->pi_name
, (int)old_state
,
535 (int)pi
->pi_adv_state
);
539 if (pi
->pi_sol_state
!= NO_SOLICIT
) {
540 int old_state
= pi
->pi_sol_state
;
542 if (debug
& (D_STATE
|D_PHYINT
)) {
543 logmsg(LOG_DEBUG
, "phyint_timer SOL(%s) "
544 "state %d\n", pi
->pi_name
, (int)old_state
);
546 next
= solicit_event(pi
, SOL_TIMER
, elapsed
);
547 if (debug
& D_STATE
) {
548 logmsg(LOG_DEBUG
, "phyint_timer SOL(%s) "
550 pi
->pi_name
, (int)old_state
,
551 (int)pi
->pi_sol_state
);
557 * If the phyint has been unplumbed, we don't want to call
558 * phyint_reach_random. We will be in the NO_ADV or NO_SOLICIT state.
560 if ((pi
->pi_AdvSendAdvertisements
&& (pi
->pi_adv_state
!= NO_ADV
)) ||
561 (!pi
->pi_AdvSendAdvertisements
&&
562 (pi
->pi_sol_state
!= NO_SOLICIT
))) {
563 pi
->pi_reach_time_since_random
+= elapsed
;
564 if (pi
->pi_reach_time_since_random
>= MAX_REACH_RANDOM_INTERVAL
)
565 phyint_reach_random(pi
, _B_TRUE
);
572 phyint_print(struct phyint
*pi
)
575 struct adv_prefix
*adv_pr
;
577 char abuf
[INET6_ADDRSTRLEN
];
579 logmsg(LOG_DEBUG
, "Phyint %s index %d state %x, kernel %x, "
581 pi
->pi_name
, pi
->pi_index
, pi
->pi_state
, pi
->pi_kernel_state
,
582 pi
->pi_num_k_routers
);
583 logmsg(LOG_DEBUG
, "\taddress: %s flags %llx\n",
584 inet_ntop(AF_INET6
, (void *)&pi
->pi_ifaddr
,
585 abuf
, sizeof (abuf
)), pi
->pi_flags
);
586 logmsg(LOG_DEBUG
, "\tsock %d mtu %d\n", pi
->pi_sock
, pi
->pi_mtu
);
587 logmsg(LOG_DEBUG
, "\ttoken: len %d %s\n", pi
->pi_token_length
,
588 inet_ntop(AF_INET6
, (void *)&pi
->pi_token
,
589 abuf
, sizeof (abuf
)));
590 if (pi
->pi_TmpAddrsEnabled
) {
591 logmsg(LOG_DEBUG
, "\ttmp_token: %s\n",
592 inet_ntop(AF_INET6
, (void *)&pi
->pi_tmp_token
,
593 abuf
, sizeof (abuf
)));
594 logmsg(LOG_DEBUG
, "\ttmp config: pref %d valid %d "
595 "maxdesync %d desync %d regen %d\n",
596 pi
->pi_TmpPreferredLifetime
, pi
->pi_TmpValidLifetime
,
597 pi
->pi_TmpMaxDesyncFactor
, pi
->pi_TmpDesyncFactor
,
598 pi
->pi_TmpRegenAdvance
);
600 if (pi
->pi_flags
& IFF_POINTOPOINT
) {
601 logmsg(LOG_DEBUG
, "\tdst_token: %s\n",
602 inet_ntop(AF_INET6
, (void *)&pi
->pi_dst_token
,
603 abuf
, sizeof (abuf
)));
605 logmsg(LOG_DEBUG
, "\tLinkMTU %d CurHopLimit %d "
606 "BaseReachableTime %d\n\tReachableTime %d RetransTimer %d\n",
607 pi
->pi_LinkMTU
, pi
->pi_CurHopLimit
, pi
->pi_BaseReachableTime
,
608 pi
->pi_ReachableTime
, pi
->pi_RetransTimer
);
609 if (!pi
->pi_AdvSendAdvertisements
) {
611 logmsg(LOG_DEBUG
, "\tSOLICIT: time_left %d state %d count %d\n",
612 pi
->pi_sol_time_left
, pi
->pi_sol_state
, pi
->pi_sol_count
);
614 /* Advertise state */
615 logmsg(LOG_DEBUG
, "\tADVERT: time_left %d state %d count %d "
617 pi
->pi_adv_time_left
, pi
->pi_adv_state
, pi
->pi_adv_count
,
618 pi
->pi_adv_time_since_sent
);
619 print_iflist(pi
->pi_config
);
621 for (pr
= pi
->pi_prefix_list
; pr
!= NULL
; pr
= pr
->pr_next
)
624 for (adv_pr
= pi
->pi_adv_prefix_list
; adv_pr
!= NULL
;
625 adv_pr
= adv_pr
->adv_pr_next
) {
626 adv_prefix_print(adv_pr
);
629 for (dr
= pi
->pi_router_list
; dr
!= NULL
; dr
= dr
->dr_next
)
632 logmsg(LOG_DEBUG
, "\n");
637 * Store the LLA for the phyint `pi' `lifrp'. Returns 0 on success, or
640 * Note that we do not cache the hardware address since there's no reliable
641 * mechanism to determine when it's become stale.
644 phyint_get_lla(struct phyint
*pi
, struct lifreq
*lifrp
)
646 struct sockaddr_in6
*sin6
;
648 /* If this phyint doesn't have a link-layer address, bail */
649 if (!(pi
->pi_flags
& IFF_MULTICAST
) ||
650 (pi
->pi_flags
& IFF_POINTOPOINT
)) {
654 (void) strlcpy(lifrp
->lifr_name
, pi
->pi_name
, LIFNAMSIZ
);
655 sin6
= (struct sockaddr_in6
*)&(lifrp
->lifr_nd
.lnr_addr
);
656 sin6
->sin6_family
= AF_INET6
;
657 sin6
->sin6_addr
= pi
->pi_ifaddr
;
658 if (ioctl(pi
->pi_sock
, SIOCLIFGETND
, lifrp
) < 0) {
660 * For IPMP interfaces, don't report ESRCH errors since that
661 * merely indicates that there are no active interfaces in the
662 * IPMP group (and thus there's no working hardware address),
663 * and the packet will thus never make it out anyway.
665 if (!(pi
->pi_flags
& IFF_IPMP
) || errno
!= ESRCH
)
666 logperror_pi(pi
, "phyint_get_lla: SIOCLIFGETND");
673 * Randomize pi->pi_ReachableTime.
674 * Done periodically when there are no RAs and at a maximum frequency when
676 * Assumes that caller has determined that it is time to generate
677 * a new random ReachableTime.
680 phyint_reach_random(struct phyint
*pi
, boolean_t set_needed
)
684 pi
->pi_ReachableTime
= GET_RANDOM(
685 (int)(ND_MIN_RANDOM_FACTOR
* pi
->pi_BaseReachableTime
),
686 (int)(ND_MAX_RANDOM_FACTOR
* pi
->pi_BaseReachableTime
));
688 bzero(&lifr
, sizeof (lifr
));
689 (void) strlcpy(lifr
.lifr_name
, pi
->pi_name
, LIFNAMSIZ
);
690 lifr
.lifr_ifinfo
.lir_reachtime
= pi
->pi_ReachableTime
;
691 if (ioctl(pi
->pi_sock
, SIOCSLIFLNKINFO
, (char *)&lifr
) < 0) {
693 "phyint_reach_random: SIOCSLIFLNKINFO");
697 pi
->pi_reach_time_since_random
= 0;
701 * Validate a temporary token against a list of known bad values.
702 * Currently assumes that token is 8 bytes long! Current known
703 * bad values include 0, reserved anycast tokens (RFC 2526), tokens
704 * used by ISATAP (draft-ietf-ngtrans-isatap-N), any token already
705 * assigned to this interface, or any token for which the global
708 * Called by tmptoken_create().
710 * Return _B_TRUE if token is valid (no match), _B_FALSE if not.
713 tmptoken_isvalid(struct in6_addr
*token
)
716 struct in6_addr mask
;
717 struct in6_addr isatap
= { 0, 0, 0, 0, 0, 0, 0, 0, \
718 0, 0, 0x5e, 0xfe, 0, 0, 0, 0 };
719 struct in6_addr anycast
= { 0, 0, 0, 0, \
721 0xfd, 0xff, 0xff, 0xff, \
722 0xff, 0xff, 0xff, 0x80 };
724 if (IN6_IS_ADDR_UNSPECIFIED(token
))
727 if (token
->s6_addr
[8] & 0x2)
730 (void) memcpy(&mask
, token
, sizeof (mask
));
731 mask
._S6_un
._S6_u32
[3] = 0;
732 if (IN6_ARE_ADDR_EQUAL(&isatap
, token
))
735 mask
._S6_un
._S6_u32
[3] = token
->_S6_un
._S6_u32
[3] & 0xffffff80;
736 if (IN6_ARE_ADDR_EQUAL(&anycast
, token
))
739 for (pi
= phyints
; pi
!= NULL
; pi
= pi
->pi_next
) {
740 if (((pi
->pi_token_length
== TMP_TOKEN_BITS
) &&
741 IN6_ARE_ADDR_EQUAL(&pi
->pi_token
, token
)) ||
742 IN6_ARE_ADDR_EQUAL(&pi
->pi_tmp_token
, token
))
746 /* none of our tests failed, must be a good one! */
751 * Generate a temporary token and set up its timer
753 * Called from incoming_prefix_addrconf_process() (when token is first
754 * needed) and from tmptoken_timer() (when current token expires).
756 * Returns _B_TRUE if a token was successfully generated, _B_FALSE if not.
759 tmptoken_create(struct phyint
*pi
)
761 int fd
, i
= 0, max_tries
= 15;
762 struct in6_addr token
;
763 uint32_t *tokenp
= &(token
._S6_un
._S6_u32
[2]);
764 char buf
[INET6_ADDRSTRLEN
];
766 if ((fd
= open("/dev/urandom", O_RDONLY
)) == -1) {
767 perror("open /dev/urandom");
771 bzero((char *)&token
, sizeof (token
));
773 if (read(fd
, (void *)tokenp
, TMP_TOKEN_BYTES
) == -1) {
774 perror("read /dev/urandom");
780 * Assume EUI-64 formatting, and thus 64-bit
781 * token len; need to clear global bit.
783 token
.s6_addr
[8] &= 0xfd;
787 } while (!tmptoken_isvalid(&token
) && i
< max_tries
);
791 if (i
== max_tries
) {
793 logmsg(LOG_WARNING
, "tmptoken_create(%s): failed to create "
794 "token; disabling temporary addresses on %s\n",
795 pi
->pi_name
, pi
->pi_name
);
796 pi
->pi_TmpAddrsEnabled
= 0;
800 pi
->pi_tmp_token
= token
;
803 logmsg(LOG_DEBUG
, "tmptoken_create(%s): created temporary "
804 "token %s\n", pi
->pi_name
,
805 inet_ntop(AF_INET6
, &pi
->pi_tmp_token
, buf
, sizeof (buf
)));
807 pi
->pi_TmpRegenCountdown
= (pi
->pi_TmpPreferredLifetime
-
808 pi
->pi_TmpDesyncFactor
- pi
->pi_TmpRegenAdvance
) * MILLISEC
;
809 if (pi
->pi_TmpRegenCountdown
!= 0)
810 timer_schedule(pi
->pi_TmpRegenCountdown
);
816 * Delete a temporary token. This is outside the normal timeout process,
817 * so mark any existing addresses based on this token DEPRECATED and set
818 * their preferred lifetime to 0. Don't tamper with valid lifetime, that
819 * will be used to eventually remove the address. Also reset the current
820 * pi_tmp_token value to 0.
822 * Called from incoming_prefix_addrconf_process() if DAD fails on a temp
826 tmptoken_delete(struct phyint
*pi
)
830 for (pr
= pi
->pi_prefix_list
; pr
!= NULL
; pr
= pr
->pr_next
) {
831 if (!(pr
->pr_flags
& IFF_TEMPORARY
) ||
832 (pr
->pr_flags
& IFF_DEPRECATED
) ||
833 (!token_equal(pr
->pr_address
, pi
->pi_tmp_token
,
837 pr
->pr_PreferredLifetime
= 0;
838 pr
->pr_state
|= PR_DEPRECATED
;
842 (void) memset(&pi
->pi_tmp_token
, 0, sizeof (pi
->pi_tmp_token
));
846 * Called from run_timeouts() with the number of milliseconds elapsed
847 * since the last call. Determines if any timeout event has occurred
848 * and returns the number of milliseconds until the next timeout event
849 * for the tmp token. Returns TIMER_INFINITY for "never".
852 tmptoken_timer(struct phyint
*pi
, uint_t elapsed
)
854 struct nd_opt_prefix_info opt
;
855 struct sockaddr_in6 sin6
;
856 struct prefix
*pr
, *newpr
;
859 logmsg(LOG_DEBUG
, "tmptoken_timer(%s, %d) regencountdown %d\n",
860 pi
->pi_name
, (int)elapsed
, pi
->pi_TmpRegenCountdown
);
862 if (!pi
->pi_TmpAddrsEnabled
||
863 (pi
->pi_TmpRegenCountdown
== TIMER_INFINITY
))
864 return (TIMER_INFINITY
);
866 if (pi
->pi_TmpRegenCountdown
> elapsed
) {
867 pi
->pi_TmpRegenCountdown
-= elapsed
;
868 return (pi
->pi_TmpRegenCountdown
);
872 * Tmp token timer has expired. Start by generating a new token.
873 * If we can't get a new token, tmp addrs are disabled on this
874 * interface, so there's no need to continue, or to set a timer.
876 if (!tmptoken_create(pi
))
877 return (TIMER_INFINITY
);
880 * Now that we have a new token, walk the list of prefixes to
881 * find which ones need a corresponding tmp addr generated.
883 for (pr
= pi
->pi_prefix_list
; pr
!= NULL
; pr
= pr
->pr_next
) {
885 if (!(pr
->pr_state
& PR_AUTO
) || pr
->pr_state
& PR_STATIC
||
886 pr
->pr_state
& PR_DEPRECATED
||
887 pr
->pr_flags
& IFF_TEMPORARY
)
890 newpr
= prefix_create(pi
, pr
->pr_prefix
, pr
->pr_prefix_len
,
893 char pbuf
[INET6_ADDRSTRLEN
];
894 char tbuf
[INET6_ADDRSTRLEN
];
895 (void) inet_ntop(AF_INET6
, &pr
->pr_prefix
, pbuf
,
897 (void) inet_ntop(AF_INET6
, &pi
->pi_tmp_token
, tbuf
,
899 logmsg(LOG_ERR
, "can't create new tmp addr "
900 "(%s, %s, %s)\n", pi
->pi_name
, pbuf
, tbuf
);
905 * We want to use incoming_prefix_*_process() functions to
906 * set up the new tmp addr, so cobble together a prefix
907 * info option struct based on the existing prefix to pass
908 * in. The lifetimes will be based on the current time
911 * The "from" param is only used for messages; pass in
914 opt
.nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
915 opt
.nd_opt_pi_len
= sizeof (opt
) / 8;
916 opt
.nd_opt_pi_prefix_len
= pr
->pr_prefix_len
;
917 opt
.nd_opt_pi_flags_reserved
= ND_OPT_PI_FLAG_AUTO
;
918 opt
.nd_opt_pi_valid_time
=
919 htonl(pr
->pr_ValidLifetime
/ 1000);
920 opt
.nd_opt_pi_preferred_time
=
921 htonl(pr
->pr_PreferredLifetime
/ 1000);
922 if (pr
->pr_state
& PR_ONLINK
)
923 opt
.nd_opt_pi_flags_reserved
&= ND_OPT_PI_FLAG_ONLINK
;
924 opt
.nd_opt_pi_prefix
= pr
->pr_prefix
;
926 (void) memset(&sin6
, 0, sizeof (sin6
));
928 if (!incoming_prefix_addrconf_process(pi
, newpr
,
929 (uchar_t
*)&opt
, &sin6
, _B_FALSE
, _B_TRUE
)) {
930 char pbuf
[INET6_ADDRSTRLEN
];
931 char tbuf
[INET6_ADDRSTRLEN
];
932 (void) inet_ntop(AF_INET6
, &pr
->pr_prefix
, pbuf
,
934 (void) inet_ntop(AF_INET6
, &pi
->pi_tmp_token
, tbuf
,
936 logmsg(LOG_ERR
, "can't create new tmp addr "
937 "(%s, %s, %s)\n", pi
->pi_name
, pbuf
, tbuf
);
941 if (pr
->pr_state
& PR_ONLINK
) {
942 incoming_prefix_onlink_process(newpr
, (uchar_t
*)&opt
);
947 * appropriate timers were scheduled when
948 * the token and addresses were created.
950 return (TIMER_INFINITY
);
954 * tlen specifies the token length in bits. Compares the lower
955 * tlen bits of the two addresses provided and returns _B_TRUE if
956 * they match, _B_FALSE if not. Also returns _B_FALSE for invalid
960 token_equal(struct in6_addr t1
, struct in6_addr t2
, int tlen
)
963 int j
, abytes
, tbytes
, tbits
;
965 if (tlen
< 0 || tlen
> IPV6_ABITS
)
968 abytes
= IPV6_ABITS
>> 3;
972 for (j
= abytes
- 1; j
>= abytes
- tbytes
; j
--)
973 if (t1
.s6_addr
[j
] != t2
.s6_addr
[j
])
979 /* We only care about the tbits rightmost bits */
980 mask
= 0xff >> (8 - tbits
);
981 if ((t1
.s6_addr
[j
] & mask
) != (t2
.s6_addr
[j
] & mask
))
988 * Lookup prefix structure that matches the prefix and prefix length.
989 * Assumes that the bits after prefixlen might not be zero.
991 static struct prefix
*
992 prefix_lookup(struct phyint
*pi
, struct in6_addr prefix
, int prefixlen
)
995 char abuf
[INET6_ADDRSTRLEN
];
997 if (debug
& D_PREFIX
) {
998 logmsg(LOG_DEBUG
, "prefix_lookup(%s, %s/%u)\n", pi
->pi_name
,
999 inet_ntop(AF_INET6
, (void *)&prefix
,
1000 abuf
, sizeof (abuf
)), prefixlen
);
1003 for (pr
= pi
->pi_prefix_list
; pr
!= NULL
; pr
= pr
->pr_next
) {
1004 if (pr
->pr_prefix_len
== prefixlen
&&
1005 prefix_equal(prefix
, pr
->pr_prefix
, prefixlen
))
1012 * Compare two prefixes that have the same prefix length.
1013 * Fails if the prefix length is unreasonable.
1016 prefix_equal(struct in6_addr p1
, struct in6_addr p2
, int plen
)
1019 int j
, pbytes
, pbits
;
1021 if (plen
< 0 || plen
> IPV6_ABITS
)
1027 for (j
= 0; j
< pbytes
; j
++)
1028 if (p1
.s6_addr
[j
] != p2
.s6_addr
[j
])
1034 /* Make the N leftmost bits one */
1035 mask
= 0xff << (8 - pbits
);
1036 if ((p1
.s6_addr
[j
] & mask
) != (p2
.s6_addr
[j
] & mask
))
1043 * Set a prefix from an address and a prefix length.
1044 * Force all the bits after the prefix length to be zero.
1047 prefix_set(struct in6_addr
*prefix
, struct in6_addr addr
, int prefix_len
)
1052 if (prefix_len
< 0 || prefix_len
> IPV6_ABITS
)
1055 bzero((char *)prefix
, sizeof (*prefix
));
1057 for (j
= 0; prefix_len
> 8; prefix_len
-= 8, j
++)
1058 prefix
->s6_addr
[j
] = addr
.s6_addr
[j
];
1060 /* Make the N leftmost bits one */
1061 mask
= 0xff << (8 - prefix_len
);
1062 prefix
->s6_addr
[j
] = addr
.s6_addr
[j
] & mask
;
1066 * Lookup a prefix based on the kernel's interface name.
1069 prefix_lookup_name(struct phyint
*pi
, char *name
)
1073 if (debug
& D_PREFIX
) {
1074 logmsg(LOG_DEBUG
, "prefix_lookup_name(%s, %s)\n",
1077 if (name
[0] == '\0')
1080 for (pr
= pi
->pi_prefix_list
; pr
!= NULL
; pr
= pr
->pr_next
) {
1081 if (strcmp(name
, pr
->pr_name
) == 0)
1088 * Search the phyints list to make sure that this new prefix does
1089 * not already exist in any other physical interfaces that have
1090 * the same address as this one
1093 prefix_lookup_addr_match(struct prefix
*pr
)
1095 char abuf
[INET6_ADDRSTRLEN
];
1097 struct prefix
*otherpr
= NULL
;
1098 struct in6_addr prefix
;
1101 if (debug
& D_PREFIX
) {
1102 logmsg(LOG_DEBUG
, "prefix_lookup_addr_match(%s/%u)\n",
1103 inet_ntop(AF_INET6
, (void *)&pr
->pr_address
,
1104 abuf
, sizeof (abuf
)), pr
->pr_prefix_len
);
1106 prefix
= pr
->pr_prefix
;
1107 prefixlen
= pr
->pr_prefix_len
;
1108 for (pi
= phyints
; pi
!= NULL
; pi
= pi
->pi_next
) {
1109 otherpr
= prefix_lookup(pi
, prefix
, prefixlen
);
1112 if (otherpr
!= NULL
&& (otherpr
->pr_state
& PR_AUTO
) &&
1113 IN6_ARE_ADDR_EQUAL(&pr
->pr_address
,
1114 &otherpr
->pr_address
))
1121 * Initialize a new prefix without setting lifetimes etc.
1124 prefix_create(struct phyint
*pi
, struct in6_addr prefix
, int prefixlen
,
1128 char abuf
[INET6_ADDRSTRLEN
];
1130 if (debug
& D_PREFIX
) {
1131 logmsg(LOG_DEBUG
, "prefix_create(%s, %s/%u, 0x%llx)\n",
1132 pi
->pi_name
, inet_ntop(AF_INET6
, (void *)&prefix
,
1133 abuf
, sizeof (abuf
)), prefixlen
, flags
);
1135 pr
= (struct prefix
*)calloc(sizeof (struct prefix
), 1);
1137 logmsg(LOG_ERR
, "prefix_create: out of memory\n");
1141 * The prefix might have non-zero bits after the prefix len bits.
1142 * Force them to be zero.
1144 prefix_set(&pr
->pr_prefix
, prefix
, prefixlen
);
1145 pr
->pr_prefix_len
= prefixlen
;
1146 pr
->pr_PreferredLifetime
= PREFIX_INFINITY
;
1147 pr
->pr_ValidLifetime
= PREFIX_INFINITY
;
1148 pr
->pr_OnLinkLifetime
= PREFIX_INFINITY
;
1149 pr
->pr_kernel_state
= 0;
1150 pr
->pr_flags
|= flags
;
1151 prefix_insert(pi
, pr
);
1156 * Create a new named prefix. Caller should use prefix_init_from_k
1157 * to initialize the content.
1160 prefix_create_name(struct phyint
*pi
, char *name
)
1164 if (debug
& D_PREFIX
) {
1165 logmsg(LOG_DEBUG
, "prefix_create_name(%s, %s)\n",
1168 pr
= (struct prefix
*)calloc(sizeof (struct prefix
), 1);
1170 logmsg(LOG_ERR
, "prefix_create_name: out of memory\n");
1173 (void) strncpy(pr
->pr_name
, name
, sizeof (pr
->pr_name
));
1174 pr
->pr_name
[sizeof (pr
->pr_name
) - 1] = '\0';
1175 prefix_insert(pi
, pr
);
1179 /* Insert in linked list */
1181 prefix_insert(struct phyint
*pi
, struct prefix
*pr
)
1183 pr
->pr_next
= pi
->pi_prefix_list
;
1185 if (pi
->pi_prefix_list
!= NULL
)
1186 pi
->pi_prefix_list
->pr_prev
= pr
;
1187 pi
->pi_prefix_list
= pr
;
1188 pr
->pr_physical
= pi
;
1192 * Initialize the prefix from the content of the kernel.
1193 * If IFF_ADDRCONF is set we treat it as PR_AUTO (i.e. an addrconf
1194 * prefix). However, we cannot derive the lifetime from
1195 * the kernel, thus it is set to 1 week.
1196 * Ignore the prefix if the interface is not IFF_UP.
1197 * If it's from DHCPv6, then we set the netmask.
1200 prefix_init_from_k(struct prefix
*pr
)
1203 struct sockaddr_in6
*sin6
;
1204 int sock
= pr
->pr_physical
->pi_sock
;
1206 (void) strncpy(lifr
.lifr_name
, pr
->pr_name
, sizeof (lifr
.lifr_name
));
1207 lifr
.lifr_name
[sizeof (lifr
.lifr_name
) - 1] = '\0';
1208 if (ioctl(sock
, SIOCGLIFADDR
, (char *)&lifr
) < 0) {
1209 logperror_pr(pr
, "prefix_init_from_k: ioctl (get addr)");
1212 if (lifr
.lifr_addr
.ss_family
!= AF_INET6
) {
1213 logmsg(LOG_ERR
, "ignoring interface %s: not AF_INET6\n",
1217 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
1218 pr
->pr_address
= sin6
->sin6_addr
;
1220 if (ioctl(sock
, SIOCGLIFFLAGS
, (char *)&lifr
) < 0) {
1221 logperror_pr(pr
, "prefix_init_from_k: ioctl (get flags)");
1224 pr
->pr_flags
= lifr
.lifr_flags
;
1227 * If this is a DHCPv6 interface, then we control the netmask.
1229 if (lifr
.lifr_flags
& IFF_DHCPRUNNING
) {
1230 struct phyint
*pi
= pr
->pr_physical
;
1233 pr
->pr_prefix_len
= IPV6_ABITS
;
1234 if (!(lifr
.lifr_flags
& IFF_UP
) ||
1235 IN6_IS_ADDR_UNSPECIFIED(&pr
->pr_address
) ||
1236 IN6_IS_ADDR_LINKLOCAL(&pr
->pr_address
)) {
1238 logmsg(LOG_DEBUG
, "prefix_init_from_k: "
1239 "ignoring DHCP %s not ready\n",
1244 for (pr2
= pi
->pi_prefix_list
; pr2
!= NULL
;
1245 pr2
= pr2
->pr_next
) {
1247 * Examine any non-static (autoconfigured) prefixes as
1248 * well as existing DHCP-controlled prefixes for valid
1249 * prefix length information.
1251 if (pr2
->pr_prefix_len
!= IPV6_ABITS
&&
1252 (!(pr2
->pr_state
& PR_STATIC
) ||
1253 (pr2
->pr_flags
& IFF_DHCPRUNNING
)) &&
1254 prefix_equal(pr
->pr_prefix
, pr2
->pr_prefix
,
1255 pr2
->pr_prefix_len
)) {
1256 pr
->pr_prefix_len
= pr2
->pr_prefix_len
;
1262 logmsg(LOG_DEBUG
, "prefix_init_from_k: no "
1263 "saved mask for DHCP %s; need to "
1264 "resolicit\n", pr
->pr_name
);
1265 (void) check_to_solicit(pi
, RESTART_INIT_SOLICIT
);
1268 logmsg(LOG_DEBUG
, "prefix_init_from_k: using "
1269 "%s mask for DHCP %s\n",
1270 pr2
->pr_name
[0] == '\0' ? "saved" :
1271 pr2
->pr_name
, pr
->pr_name
);
1272 prefix_update_dhcp(pr
);
1275 * If this interface was created using ipadm, store the
1276 * addrobj for the DHCPv6 interface in ipmgmtd daemon's
1277 * in-memory aobjmap.
1279 prefix_update_ipadm_addrobj(pr
, _B_TRUE
);
1281 if (ioctl(sock
, SIOCGLIFSUBNET
, (char *)&lifr
) < 0) {
1283 "prefix_init_from_k: ioctl (get subnet)");
1286 if (lifr
.lifr_subnet
.ss_family
!= AF_INET6
) {
1288 "ignoring interface %s: not AF_INET6\n",
1293 * Guard against the prefix having non-zero bits after the
1296 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_subnet
;
1297 pr
->pr_prefix_len
= lifr
.lifr_addrlen
;
1298 prefix_set(&pr
->pr_prefix
, sin6
->sin6_addr
, pr
->pr_prefix_len
);
1300 if (pr
->pr_prefix_len
!= IPV6_ABITS
&&
1301 (pr
->pr_flags
& IFF_UP
) &&
1302 IN6_ARE_ADDR_EQUAL(&pr
->pr_address
, &pr
->pr_prefix
)) {
1303 char abuf
[INET6_ADDRSTRLEN
];
1305 logmsg(LOG_ERR
, "ignoring interface %s: it appears to "
1306 "be configured with an invalid interface id "
1309 inet_ntop(AF_INET6
, (void *)&pr
->pr_address
,
1310 abuf
, sizeof (abuf
)), pr
->pr_prefix_len
);
1314 pr
->pr_kernel_state
= 0;
1315 if (pr
->pr_prefix_len
!= IPV6_ABITS
)
1316 pr
->pr_kernel_state
|= PR_ONLINK
;
1317 if (!(pr
->pr_flags
& (IFF_NOLOCAL
| IFF_DHCPRUNNING
)))
1318 pr
->pr_kernel_state
|= PR_AUTO
;
1319 if ((pr
->pr_flags
& IFF_DEPRECATED
) && (pr
->pr_kernel_state
& PR_AUTO
))
1320 pr
->pr_kernel_state
|= PR_DEPRECATED
;
1321 if (!(pr
->pr_flags
& IFF_ADDRCONF
)) {
1322 /* Prevent ndpd from stepping on this prefix */
1323 pr
->pr_kernel_state
|= PR_STATIC
;
1325 pr
->pr_state
= pr
->pr_kernel_state
;
1326 /* Adjust pr_prefix_len based if PR_AUTO is set */
1327 if (pr
->pr_state
& PR_AUTO
) {
1329 IPV6_ABITS
- pr
->pr_physical
->pi_token_length
;
1330 prefix_set(&pr
->pr_prefix
, pr
->pr_prefix
, pr
->pr_prefix_len
);
1333 /* Can't extract lifetimes from the kernel - use 1 week */
1334 pr
->pr_ValidLifetime
= NDP_PREFIX_DEFAULT_LIFETIME
;
1335 pr
->pr_PreferredLifetime
= NDP_PREFIX_DEFAULT_LIFETIME
;
1336 pr
->pr_OnLinkLifetime
= NDP_PREFIX_DEFAULT_LIFETIME
;
1339 * If this is a temp addr, the creation time needs to be set.
1340 * Though it won't be entirely accurate, the current time is
1341 * an okay approximation.
1343 if (pr
->pr_flags
& IFF_TEMPORARY
)
1344 pr
->pr_CreateTime
= getcurrenttime() / MILLISEC
;
1346 if (pr
->pr_kernel_state
== 0)
1347 pr
->pr_name
[0] = '\0';
1351 /* Pretend that the prefix does not exist in the kernel */
1352 pr
->pr_kernel_state
= 0;
1353 pr
->pr_name
[0] = '\0';
1358 * Delete (unlink and free) and remove from kernel if the prefix
1359 * was added by in.ndpd (i.e. PR_STATIC is not set).
1360 * Handles delete of things that have not yet been inserted in the list
1361 * i.e. pr_physical is NULL.
1362 * Removes the ipadm addrobj created for the prefix.
1365 prefix_delete(struct prefix
*pr
)
1368 char abuf
[INET6_ADDRSTRLEN
];
1370 if (debug
& D_PREFIX
) {
1371 logmsg(LOG_DEBUG
, "prefix_delete(%s, %s, %s/%u)\n",
1372 pr
->pr_physical
->pi_name
, pr
->pr_name
,
1373 inet_ntop(AF_INET6
, (void *)&pr
->pr_prefix
,
1374 abuf
, sizeof (abuf
)), pr
->pr_prefix_len
);
1376 pi
= pr
->pr_physical
;
1378 /* Remove non-static prefixes from the kernel. */
1379 pr
->pr_state
&= PR_STATIC
;
1380 if (pr
->pr_kernel_state
!= pr
->pr_state
)
1381 prefix_update_k(pr
);
1383 if (pr
->pr_prev
== NULL
) {
1385 pi
->pi_prefix_list
= pr
->pr_next
;
1387 pr
->pr_prev
->pr_next
= pr
->pr_next
;
1389 if (pr
->pr_next
!= NULL
)
1390 pr
->pr_next
->pr_prev
= pr
->pr_prev
;
1391 pr
->pr_next
= pr
->pr_prev
= NULL
;
1397 * Toggle one or more IFF_ flags for a prefix. Turn on 'onflags' and
1398 * turn off 'offflags'.
1401 prefix_modify_flags(struct prefix
*pr
, uint64_t onflags
, uint64_t offflags
)
1404 struct phyint
*pi
= pr
->pr_physical
;
1406 char abuf
[INET6_ADDRSTRLEN
];
1408 if (debug
& D_PREFIX
) {
1409 logmsg(LOG_DEBUG
, "prefix_modify_flags(%s, %s, %s/%u) "
1410 "flags %llx on %llx off %llx\n",
1411 pr
->pr_physical
->pi_name
,
1413 inet_ntop(AF_INET6
, (void *)&pr
->pr_prefix
,
1414 abuf
, sizeof (abuf
)), pr
->pr_prefix_len
,
1415 pr
->pr_flags
, onflags
, offflags
);
1417 /* Assumes that only the PR_STATIC link-local matches the pi_name */
1418 if (!(pr
->pr_state
& PR_STATIC
) &&
1419 strcmp(pr
->pr_name
, pi
->pi_name
) == 0) {
1420 logmsg(LOG_ERR
, "prefix_modify_flags(%s, on %llx, off %llx): "
1421 "name matches interface name\n",
1422 pi
->pi_name
, onflags
, offflags
);
1426 (void) strncpy(lifr
.lifr_name
, pr
->pr_name
, sizeof (lifr
.lifr_name
));
1427 lifr
.lifr_name
[sizeof (lifr
.lifr_name
) - 1] = '\0';
1428 if (ioctl(pi
->pi_sock
, SIOCGLIFFLAGS
, (char *)&lifr
) < 0) {
1429 if (errno
!= ENXIO
) {
1430 logperror_pr(pr
, "prefix_modify_flags: SIOCGLIFFLAGS");
1431 logmsg(LOG_ERR
, "prefix_modify_flags(%s, %s) old 0x%llx"
1432 " on 0x%llx off 0x%llx\n", pr
->pr_physical
->pi_name
,
1433 pr
->pr_name
, pr
->pr_flags
, onflags
, offflags
);
1437 old_flags
= lifr
.lifr_flags
;
1438 lifr
.lifr_flags
|= onflags
;
1439 lifr
.lifr_flags
&= ~offflags
;
1440 pr
->pr_flags
= lifr
.lifr_flags
;
1441 if (ioctl(pi
->pi_sock
, SIOCSLIFFLAGS
, (char *)&lifr
) < 0) {
1442 if (errno
!= ENXIO
) {
1443 logperror_pr(pr
, "prefix_modify_flags: SIOCSLIFFLAGS");
1444 logmsg(LOG_ERR
, "prefix_modify_flags(%s, %s) old 0x%llx"
1445 " new 0x%llx on 0x%llx off 0x%llx\n",
1446 pr
->pr_physical
->pi_name
, pr
->pr_name
,
1447 old_flags
, lifr
.lifr_flags
, onflags
, offflags
);
1455 * Update the subnet mask for this interface under DHCPv6 control.
1458 prefix_update_dhcp(struct prefix
*pr
)
1462 (void) memset(&lifr
, 0, sizeof (lifr
));
1463 (void) strlcpy(lifr
.lifr_name
, pr
->pr_name
, sizeof (lifr
.lifr_name
));
1464 lifr
.lifr_addr
.ss_family
= AF_INET6
;
1465 prefix_set(&((struct sockaddr_in6
*)&lifr
.lifr_addr
)->sin6_addr
,
1466 pr
->pr_address
, pr
->pr_prefix_len
);
1467 lifr
.lifr_addrlen
= pr
->pr_prefix_len
;
1469 * Ignore ENXIO, as the dhcpagent process is responsible for plumbing
1470 * and unplumbing these.
1472 if (ioctl(pr
->pr_physical
->pi_sock
, SIOCSLIFSUBNET
, (char *)&lifr
) ==
1473 -1 && errno
!= ENXIO
)
1474 logperror_pr(pr
, "prefix_update_dhcp: ioctl (set subnet)");
1478 * Make the kernel state match what is in the prefix structure.
1479 * This includes creating the prefix (allocating a new interface name)
1480 * as well as setting the local address and on-link subnet prefix
1481 * and controlling the IFF_ADDRCONF and IFF_DEPRECATED flags.
1484 prefix_update_k(struct prefix
*pr
)
1487 char abuf
[INET6_ADDRSTRLEN
];
1488 char buf1
[PREFIX_STATESTRLEN
], buf2
[PREFIX_STATESTRLEN
];
1489 struct phyint
*pi
= pr
->pr_physical
;
1490 struct sockaddr_in6
*sin6
;
1492 if (debug
& D_PREFIX
) {
1493 logmsg(LOG_DEBUG
, "prefix_update_k(%s, %s, %s/%u) "
1494 "from %s to %s\n", pr
->pr_physical
->pi_name
, pr
->pr_name
,
1495 inet_ntop(AF_INET6
, (void *)&pr
->pr_prefix
,
1496 abuf
, sizeof (abuf
)), pr
->pr_prefix_len
,
1497 prefix_print_state(pr
->pr_kernel_state
, buf1
,
1499 prefix_print_state(pr
->pr_state
, buf2
, sizeof (buf2
)));
1502 if (pr
->pr_kernel_state
== pr
->pr_state
)
1503 return; /* No changes */
1505 /* Skip static prefixes */
1506 if (pr
->pr_state
& PR_STATIC
)
1509 if (pr
->pr_kernel_state
== 0) {
1512 * Create a new logical interface name and store in pr_name.
1513 * Set IFF_ADDRCONF. Do not set an address (yet).
1515 if (pr
->pr_name
[0] != '\0') {
1516 /* Name already set! */
1517 logmsg(LOG_ERR
, "prefix_update_k(%s, %s, %s/%u) "
1518 "from %s to %s name is already allocated\n",
1519 pr
->pr_physical
->pi_name
, pr
->pr_name
,
1520 inet_ntop(AF_INET6
, (void *)&pr
->pr_prefix
,
1521 abuf
, sizeof (abuf
)), pr
->pr_prefix_len
,
1522 prefix_print_state(pr
->pr_kernel_state
, buf1
,
1524 prefix_print_state(pr
->pr_state
, buf2
,
1529 (void) strncpy(lifr
.lifr_name
, pi
->pi_name
,
1530 sizeof (lifr
.lifr_name
));
1531 lifr
.lifr_name
[sizeof (lifr
.lifr_name
) - 1] = '\0';
1532 lifr
.lifr_addr
.ss_family
= AF_UNSPEC
;
1533 if (ioctl(pi
->pi_sock
, SIOCLIFADDIF
, (char *)&lifr
) < 0) {
1534 logperror_pr(pr
, "prefix_update_k: SIOCLIFADDIF");
1537 (void) strncpy(pr
->pr_name
, lifr
.lifr_name
,
1538 sizeof (pr
->pr_name
));
1539 pr
->pr_name
[sizeof (pr
->pr_name
) - 1] = '\0';
1540 if (debug
& D_PREFIX
) {
1541 logmsg(LOG_DEBUG
, "prefix_update_k: new name %s\n",
1545 * The IFF_TEMPORARY flag might have already been set; if
1546 * so, it needs to be or'd into the flags we're turning on.
1547 * But be careful, we might be re-creating a manually
1548 * removed interface, in which case we don't want to try
1549 * to set *all* the flags we might have in our copy of the
1552 onflags
= IFF_ADDRCONF
;
1553 if (pr
->pr_flags
& IFF_TEMPORARY
)
1554 onflags
|= IFF_TEMPORARY
;
1555 if (prefix_modify_flags(pr
, onflags
, 0) == -1)
1558 if ((pr
->pr_state
& (PR_ONLINK
|PR_AUTO
)) == 0) {
1559 /* Remove the interface */
1560 if (prefix_modify_flags(pr
, 0, IFF_UP
|IFF_DEPRECATED
) == -1)
1562 (void) strncpy(lifr
.lifr_name
, pr
->pr_name
,
1563 sizeof (lifr
.lifr_name
));
1564 lifr
.lifr_name
[sizeof (lifr
.lifr_name
) - 1] = '\0';
1566 if (debug
& D_PREFIX
) {
1567 logmsg(LOG_DEBUG
, "prefix_update_k: remove name %s\n",
1572 * Assumes that only the PR_STATIC link-local matches
1575 if (!(pr
->pr_state
& PR_STATIC
) &&
1576 strcmp(pr
->pr_name
, pi
->pi_name
) == 0) {
1577 logmsg(LOG_ERR
, "prefix_update_k(%s): "
1578 "name matches if\n", pi
->pi_name
);
1582 /* Remove logical interface based on pr_name */
1583 lifr
.lifr_addr
.ss_family
= AF_UNSPEC
;
1584 if (ioctl(pi
->pi_sock
, SIOCLIFREMOVEIF
, (char *)&lifr
) < 0 &&
1586 logperror_pr(pr
, "prefix_update_k: SIOCLIFREMOVEIF");
1588 pr
->pr_kernel_state
= 0;
1589 pr
->pr_name
[0] = '\0';
1592 if ((pr
->pr_state
& PR_AUTO
) && !(pr
->pr_kernel_state
& PR_AUTO
)) {
1594 * Set local address and set the prefix length to 128.
1595 * Turn off IFF_NOLOCAL in case it was set.
1598 (void) strncpy(lifr
.lifr_name
, pr
->pr_name
,
1599 sizeof (lifr
.lifr_name
));
1600 lifr
.lifr_name
[sizeof (lifr
.lifr_name
) - 1] = '\0';
1601 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
1602 bzero(sin6
, sizeof (struct sockaddr_in6
));
1603 sin6
->sin6_family
= AF_INET6
;
1604 sin6
->sin6_addr
= pr
->pr_address
;
1605 if (debug
& D_PREFIX
) {
1606 logmsg(LOG_DEBUG
, "prefix_update_k(%s) set addr %s "
1609 inet_ntop(AF_INET6
, (void *)&pr
->pr_address
,
1610 abuf
, sizeof (abuf
)));
1612 if (ioctl(pi
->pi_sock
, SIOCSLIFADDR
, (char *)&lifr
) < 0) {
1613 logperror_pr(pr
, "prefix_update_k: SIOCSLIFADDR");
1617 * If this interface was created using ipadm, store the
1618 * addrobj for the prefix in ipmgmtd daemon's aobjmap.
1620 prefix_update_ipadm_addrobj(pr
, _B_TRUE
);
1621 if (pr
->pr_state
& PR_ONLINK
) {
1622 sin6
->sin6_addr
= pr
->pr_prefix
;
1623 lifr
.lifr_addrlen
= pr
->pr_prefix_len
;
1625 sin6
->sin6_addr
= pr
->pr_address
;
1626 lifr
.lifr_addrlen
= IPV6_ABITS
;
1628 if (debug
& D_PREFIX
) {
1629 logmsg(LOG_DEBUG
, "prefix_update_k(%s) set subnet "
1630 "%s/%u for PR_AUTO on\n", pr
->pr_name
,
1631 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
1632 abuf
, sizeof (abuf
)), lifr
.lifr_addrlen
);
1634 if (ioctl(pi
->pi_sock
, SIOCSLIFSUBNET
, (char *)&lifr
) < 0) {
1635 logperror_pr(pr
, "prefix_update_k: SIOCSLIFSUBNET");
1639 * For ptp interfaces, create a destination based on
1640 * prefix and prefix len together with the remote token
1641 * extracted from the remote pt-pt address. This is used by
1642 * ip to choose a proper source for outgoing packets.
1644 if (pi
->pi_flags
& IFF_POINTOPOINT
) {
1647 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
1648 bzero(sin6
, sizeof (struct sockaddr_in6
));
1649 sin6
->sin6_family
= AF_INET6
;
1650 sin6
->sin6_addr
= pr
->pr_prefix
;
1651 for (i
= 0; i
< 16; i
++) {
1652 sin6
->sin6_addr
.s6_addr
[i
] |=
1653 pi
->pi_dst_token
.s6_addr
[i
];
1655 if (debug
& D_PREFIX
) {
1656 logmsg(LOG_DEBUG
, "prefix_update_k(%s) "
1657 "set dstaddr %s for PR_AUTO on\n",
1658 pr
->pr_name
, inet_ntop(AF_INET6
,
1659 (void *)&sin6
->sin6_addr
,
1660 abuf
, sizeof (abuf
)));
1662 if (ioctl(pi
->pi_sock
, SIOCSLIFDSTADDR
,
1663 (char *)&lifr
) < 0) {
1665 "prefix_update_k: SIOCSLIFDSTADDR");
1669 if (prefix_modify_flags(pr
, IFF_UP
, IFF_NOLOCAL
) == -1)
1671 pr
->pr_kernel_state
|= PR_AUTO
;
1672 if (pr
->pr_state
& PR_ONLINK
)
1673 pr
->pr_kernel_state
|= PR_ONLINK
;
1675 pr
->pr_kernel_state
&= ~PR_ONLINK
;
1677 if (!(pr
->pr_state
& PR_AUTO
) && (pr
->pr_kernel_state
& PR_AUTO
)) {
1678 /* Turn on IFF_NOLOCAL and set the local address to all zero */
1679 if (prefix_modify_flags(pr
, IFF_NOLOCAL
, 0) == -1)
1681 (void) strncpy(lifr
.lifr_name
, pr
->pr_name
,
1682 sizeof (lifr
.lifr_name
));
1683 lifr
.lifr_name
[sizeof (lifr
.lifr_name
) - 1] = '\0';
1684 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
1685 bzero(sin6
, sizeof (struct sockaddr_in6
));
1686 sin6
->sin6_family
= AF_INET6
;
1687 if (debug
& D_PREFIX
) {
1688 logmsg(LOG_DEBUG
, "prefix_update_k(%s) set addr %s "
1689 "for PR_AUTO off\n", pr
->pr_name
,
1690 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
1691 abuf
, sizeof (abuf
)));
1693 if (ioctl(pi
->pi_sock
, SIOCSLIFADDR
, (char *)&lifr
) < 0) {
1694 logperror_pr(pr
, "prefix_update_k: SIOCSLIFADDR");
1697 pr
->pr_kernel_state
&= ~PR_AUTO
;
1699 if ((pr
->pr_state
& PR_DEPRECATED
) &&
1700 !(pr
->pr_kernel_state
& PR_DEPRECATED
) &&
1701 (pr
->pr_kernel_state
& PR_AUTO
)) {
1702 /* Only applies if PR_AUTO */
1703 if (prefix_modify_flags(pr
, IFF_DEPRECATED
, 0) == -1)
1705 pr
->pr_kernel_state
|= PR_DEPRECATED
;
1707 if (!(pr
->pr_state
& PR_DEPRECATED
) &&
1708 (pr
->pr_kernel_state
& PR_DEPRECATED
)) {
1709 if (prefix_modify_flags(pr
, 0, IFF_DEPRECATED
) == -1)
1711 pr
->pr_kernel_state
&= ~PR_DEPRECATED
;
1713 if ((pr
->pr_state
& PR_ONLINK
) && !(pr
->pr_kernel_state
& PR_ONLINK
)) {
1714 /* Set the subnet and set IFF_UP */
1715 (void) strncpy(lifr
.lifr_name
, pr
->pr_name
,
1716 sizeof (lifr
.lifr_name
));
1717 lifr
.lifr_name
[sizeof (lifr
.lifr_name
) - 1] = '\0';
1718 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
1719 bzero(sin6
, sizeof (struct sockaddr_in6
));
1720 sin6
->sin6_family
= AF_INET6
;
1721 sin6
->sin6_addr
= pr
->pr_prefix
;
1722 lifr
.lifr_addrlen
= pr
->pr_prefix_len
;
1723 if (debug
& D_PREFIX
) {
1724 logmsg(LOG_DEBUG
, "prefix_update_k(%s) set subnet "
1725 "%s/%d for PR_ONLINK on\n", pr
->pr_name
,
1726 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
1727 abuf
, sizeof (abuf
)), lifr
.lifr_addrlen
);
1729 if (ioctl(pi
->pi_sock
, SIOCSLIFSUBNET
, (char *)&lifr
) < 0) {
1730 logperror_pr(pr
, "prefix_update_k: SIOCSLIFSUBNET");
1734 * If we've previously marked the interface "up" while
1735 * processing the PR_AUTO flag -- via incoming_prefix_addrconf
1736 * -- then there's no need to set it "up" again. We're done;
1737 * just set PR_ONLINK to indicate that we've set the subnet.
1739 if (!(pr
->pr_state
& PR_AUTO
) &&
1740 prefix_modify_flags(pr
, IFF_UP
| IFF_NOLOCAL
, 0) == -1)
1742 pr
->pr_kernel_state
|= PR_ONLINK
;
1744 if (!(pr
->pr_state
& PR_ONLINK
) && (pr
->pr_kernel_state
& PR_ONLINK
)) {
1745 /* Set the prefixlen to 128 */
1746 (void) strncpy(lifr
.lifr_name
, pr
->pr_name
,
1747 sizeof (lifr
.lifr_name
));
1748 lifr
.lifr_name
[sizeof (lifr
.lifr_name
) - 1] = '\0';
1749 sin6
= (struct sockaddr_in6
*)&lifr
.lifr_addr
;
1750 bzero(sin6
, sizeof (struct sockaddr_in6
));
1751 sin6
->sin6_family
= AF_INET6
;
1752 sin6
->sin6_addr
= pr
->pr_address
;
1753 lifr
.lifr_addrlen
= IPV6_ABITS
;
1754 if (debug
& D_PREFIX
) {
1755 logmsg(LOG_DEBUG
, "prefix_update_k(%s) set subnet "
1756 "%s/%d for PR_ONLINK off\n", pr
->pr_name
,
1757 inet_ntop(AF_INET6
, (void *)&sin6
->sin6_addr
,
1758 abuf
, sizeof (abuf
)), lifr
.lifr_addrlen
);
1760 if (ioctl(pi
->pi_sock
, SIOCSLIFSUBNET
, (char *)&lifr
) < 0) {
1761 logperror_pr(pr
, "prefix_update_k: SIOCSLIFSUBNET");
1764 pr
->pr_kernel_state
&= ~PR_ONLINK
;
1769 * Called with the number of millseconds elapsed since the last call.
1770 * Determines if any timeout event has occurred and
1771 * returns the number of milliseconds until the next timeout event.
1772 * Returns TIMER_INFINITY for "never".
1775 prefix_timer(struct prefix
*pr
, uint_t elapsed
)
1777 uint_t next
= TIMER_INFINITY
;
1778 char abuf
[INET6_ADDRSTRLEN
];
1780 if (debug
& (D_PREFIX
|D_TMP
)) {
1781 logmsg(LOG_DEBUG
, "prefix_timer(%s, %s/%u, %d) "
1782 "valid %d pref %d onlink %d\n",
1784 inet_ntop(AF_INET6
, (void *)&pr
->pr_prefix
,
1785 abuf
, sizeof (abuf
)), pr
->pr_prefix_len
,
1786 elapsed
, pr
->pr_ValidLifetime
, pr
->pr_PreferredLifetime
,
1787 pr
->pr_OnLinkLifetime
);
1790 /* Exclude static prefixes */
1791 if (pr
->pr_state
& PR_STATIC
)
1794 if (pr
->pr_AutonomousFlag
&&
1795 (pr
->pr_PreferredLifetime
!= PREFIX_INFINITY
)) {
1796 if (pr
->pr_PreferredLifetime
<= elapsed
) {
1797 pr
->pr_PreferredLifetime
= 0;
1799 pr
->pr_PreferredLifetime
-= elapsed
;
1800 if (pr
->pr_PreferredLifetime
< next
)
1801 next
= pr
->pr_PreferredLifetime
;
1804 if (pr
->pr_AutonomousFlag
&&
1805 (pr
->pr_ValidLifetime
!= PREFIX_INFINITY
)) {
1806 if (pr
->pr_ValidLifetime
<= elapsed
) {
1807 pr
->pr_ValidLifetime
= 0;
1809 pr
->pr_ValidLifetime
-= elapsed
;
1810 if (pr
->pr_ValidLifetime
< next
)
1811 next
= pr
->pr_ValidLifetime
;
1814 if (pr
->pr_OnLinkFlag
&&
1815 (pr
->pr_OnLinkLifetime
!= PREFIX_INFINITY
)) {
1816 if (pr
->pr_OnLinkLifetime
<= elapsed
) {
1817 pr
->pr_OnLinkLifetime
= 0;
1819 pr
->pr_OnLinkLifetime
-= elapsed
;
1820 if (pr
->pr_OnLinkLifetime
< next
)
1821 next
= pr
->pr_OnLinkLifetime
;
1824 if (pr
->pr_AutonomousFlag
&& pr
->pr_ValidLifetime
== 0)
1825 pr
->pr_state
&= ~(PR_AUTO
|PR_DEPRECATED
);
1826 if (pr
->pr_AutonomousFlag
&& pr
->pr_PreferredLifetime
== 0 &&
1827 (pr
->pr_state
& PR_AUTO
)) {
1828 pr
->pr_state
|= PR_DEPRECATED
;
1830 logmsg(LOG_WARNING
, "prefix_timer: deprecated "
1831 "prefix(%s)\n", pr
->pr_name
);
1833 if (pr
->pr_OnLinkFlag
&& pr
->pr_OnLinkLifetime
== 0)
1834 pr
->pr_state
&= ~PR_ONLINK
;
1836 if (pr
->pr_state
!= pr
->pr_kernel_state
) {
1837 /* Might cause prefix to be deleted! */
1839 /* Log a message when an addrconf prefix goes away */
1840 if ((pr
->pr_kernel_state
& PR_AUTO
) &&
1841 !(pr
->pr_state
& PR_AUTO
)) {
1842 char abuf
[INET6_ADDRSTRLEN
];
1845 "Address removed due to timeout %s\n",
1846 inet_ntop(AF_INET6
, (void *)&pr
->pr_address
,
1847 abuf
, sizeof (abuf
)));
1849 prefix_update_k(pr
);
1856 prefix_print_state(int state
, char *buf
, int buflen
)
1864 if (state
& PR_ONLINK
) {
1865 if (strlcat(cp
, "ONLINK ", cplen
) >= cplen
)
1868 cplen
= buflen
- (cp
- buf
);
1870 if (state
& PR_AUTO
) {
1871 if (strlcat(cp
, "AUTO ", cplen
) >= cplen
)
1874 cplen
= buflen
- (cp
- buf
);
1876 if (state
& PR_DEPRECATED
) {
1877 if (strlcat(cp
, "DEPRECATED ", cplen
) >= cplen
)
1880 cplen
= buflen
- (cp
- buf
);
1882 if (state
& PR_STATIC
) {
1883 if (strlcat(cp
, "STATIC ", cplen
) >= cplen
)
1886 cplen
= buflen
- (cp
- buf
);
1892 prefix_print(struct prefix
*pr
)
1894 char abuf
[INET6_ADDRSTRLEN
];
1895 char buf1
[PREFIX_STATESTRLEN
], buf2
[PREFIX_STATESTRLEN
];
1897 logmsg(LOG_DEBUG
, "Prefix name: %s prefix %s/%u state %s "
1898 "kernel_state %s\n", pr
->pr_name
,
1899 inet_ntop(AF_INET6
, (void *)&pr
->pr_prefix
, abuf
, sizeof (abuf
)),
1901 prefix_print_state(pr
->pr_state
, buf2
, sizeof (buf2
)),
1902 prefix_print_state(pr
->pr_kernel_state
, buf1
, sizeof (buf1
)));
1903 logmsg(LOG_DEBUG
, "\tAddress: %s flags %llx in_use %d\n",
1904 inet_ntop(AF_INET6
, (void *)&pr
->pr_address
, abuf
, sizeof (abuf
)),
1905 pr
->pr_flags
, pr
->pr_in_use
);
1906 logmsg(LOG_DEBUG
, "\tValidLifetime %u PreferredLifetime %u "
1907 "OnLinkLifetime %u\n", pr
->pr_ValidLifetime
,
1908 pr
->pr_PreferredLifetime
, pr
->pr_OnLinkLifetime
);
1909 logmsg(LOG_DEBUG
, "\tOnLink %d Auto %d\n",
1910 pr
->pr_OnLinkFlag
, pr
->pr_AutonomousFlag
);
1911 logmsg(LOG_DEBUG
, "\n");
1915 * Lookup advertisement prefix structure that matches the prefix and
1917 * Assumes that the bits after prefixlen might not be zero.
1920 adv_prefix_lookup(struct phyint
*pi
, struct in6_addr prefix
, int prefixlen
)
1922 struct adv_prefix
*adv_pr
;
1923 char abuf
[INET6_ADDRSTRLEN
];
1925 if (debug
& D_PREFIX
) {
1926 logmsg(LOG_DEBUG
, "adv_prefix_lookup(%s, %s/%u)\n",
1927 pi
->pi_name
, inet_ntop(AF_INET6
, (void *)&prefix
,
1928 abuf
, sizeof (abuf
)), prefixlen
);
1931 for (adv_pr
= pi
->pi_adv_prefix_list
; adv_pr
!= NULL
;
1932 adv_pr
= adv_pr
->adv_pr_next
) {
1933 if (adv_pr
->adv_pr_prefix_len
== prefixlen
&&
1934 prefix_equal(prefix
, adv_pr
->adv_pr_prefix
, prefixlen
))
1941 * Initialize a new advertisement prefix.
1944 adv_prefix_create(struct phyint
*pi
, struct in6_addr prefix
, int prefixlen
)
1946 struct adv_prefix
*adv_pr
;
1947 char abuf
[INET6_ADDRSTRLEN
];
1949 if (debug
& D_PREFIX
) {
1950 logmsg(LOG_DEBUG
, "adv_prefix_create(%s, %s/%u)\n",
1951 pi
->pi_name
, inet_ntop(AF_INET6
, (void *)&prefix
,
1952 abuf
, sizeof (abuf
)), prefixlen
);
1954 adv_pr
= (struct adv_prefix
*)calloc(sizeof (struct adv_prefix
), 1);
1955 if (adv_pr
== NULL
) {
1956 logmsg(LOG_ERR
, "adv_prefix_create: calloc\n");
1960 * The prefix might have non-zero bits after the prefix len bits.
1961 * Force them to be zero.
1963 prefix_set(&adv_pr
->adv_pr_prefix
, prefix
, prefixlen
);
1964 adv_pr
->adv_pr_prefix_len
= prefixlen
;
1965 adv_prefix_insert(pi
, adv_pr
);
1969 /* Insert in linked list */
1971 adv_prefix_insert(struct phyint
*pi
, struct adv_prefix
*adv_pr
)
1973 adv_pr
->adv_pr_next
= pi
->pi_adv_prefix_list
;
1974 adv_pr
->adv_pr_prev
= NULL
;
1975 if (pi
->pi_adv_prefix_list
!= NULL
)
1976 pi
->pi_adv_prefix_list
->adv_pr_prev
= adv_pr
;
1977 pi
->pi_adv_prefix_list
= adv_pr
;
1978 adv_pr
->adv_pr_physical
= pi
;
1982 * Delete (unlink and free) from our tables. There should be
1983 * a corresponding "struct prefix *" which will clean up the kernel
1984 * if necessary. adv_prefix is just used for sending out advertisements.
1987 adv_prefix_delete(struct adv_prefix
*adv_pr
)
1990 char abuf
[INET6_ADDRSTRLEN
];
1992 if (debug
& D_PREFIX
) {
1993 logmsg(LOG_DEBUG
, "adv_prefix_delete(%s, %s/%u)\n",
1994 adv_pr
->adv_pr_physical
->pi_name
,
1995 inet_ntop(AF_INET6
, (void *)&adv_pr
->adv_pr_prefix
,
1996 abuf
, sizeof (abuf
)), adv_pr
->adv_pr_prefix_len
);
1998 pi
= adv_pr
->adv_pr_physical
;
2000 if (adv_pr
->adv_pr_prev
== NULL
) {
2002 pi
->pi_adv_prefix_list
= adv_pr
->adv_pr_next
;
2004 adv_pr
->adv_pr_prev
->adv_pr_next
= adv_pr
->adv_pr_next
;
2006 if (adv_pr
->adv_pr_next
!= NULL
)
2007 adv_pr
->adv_pr_next
->adv_pr_prev
= adv_pr
->adv_pr_prev
;
2008 adv_pr
->adv_pr_next
= adv_pr
->adv_pr_prev
= NULL
;
2013 * Called with the number of millseconds elapsed since the last call.
2014 * Determines if any timeout event has occurred and
2015 * returns the number of milliseconds until the next timeout event.
2016 * Returns TIMER_INFINITY for "never".
2019 adv_prefix_timer(struct adv_prefix
*adv_pr
, uint_t elapsed
)
2021 int seconds_elapsed
= (elapsed
+ 500) / 1000; /* Rounded */
2022 char abuf
[INET6_ADDRSTRLEN
];
2024 if (debug
& D_PREFIX
) {
2025 logmsg(LOG_DEBUG
, "adv_prefix_timer(%s, %s/%u, %d)\n",
2026 adv_pr
->adv_pr_physical
->pi_name
,
2027 inet_ntop(AF_INET6
, (void *)&adv_pr
->adv_pr_prefix
,
2028 abuf
, sizeof (abuf
)), adv_pr
->adv_pr_prefix_len
,
2032 /* Decrement Expire time left for real-time lifetimes */
2033 if (adv_pr
->adv_pr_AdvValidRealTime
) {
2034 if (adv_pr
->adv_pr_AdvValidExpiration
> seconds_elapsed
)
2035 adv_pr
->adv_pr_AdvValidExpiration
-= seconds_elapsed
;
2037 adv_pr
->adv_pr_AdvValidExpiration
= 0;
2039 if (adv_pr
->adv_pr_AdvPreferredRealTime
) {
2040 if (adv_pr
->adv_pr_AdvPreferredExpiration
> seconds_elapsed
) {
2041 adv_pr
->adv_pr_AdvPreferredExpiration
-=
2044 adv_pr
->adv_pr_AdvPreferredExpiration
= 0;
2047 return (TIMER_INFINITY
);
2051 adv_prefix_print(struct adv_prefix
*adv_pr
)
2053 print_prefixlist(adv_pr
->adv_pr_config
);
2056 /* Lookup router on its link-local IPv6 address */
2058 router_lookup(struct phyint
*pi
, struct in6_addr addr
)
2061 char abuf
[INET6_ADDRSTRLEN
];
2063 if (debug
& D_ROUTER
) {
2064 logmsg(LOG_DEBUG
, "router_lookup(%s, %s)\n", pi
->pi_name
,
2065 inet_ntop(AF_INET6
, (void *)&addr
,
2066 abuf
, sizeof (abuf
)));
2069 for (dr
= pi
->pi_router_list
; dr
!= NULL
; dr
= dr
->dr_next
) {
2070 if (bcmp((char *)&addr
, (char *)&dr
->dr_address
,
2071 sizeof (addr
)) == 0)
2078 * Create a default router entry.
2079 * The lifetime parameter is in seconds.
2082 router_create(struct phyint
*pi
, struct in6_addr addr
, uint_t lifetime
)
2085 char abuf
[INET6_ADDRSTRLEN
];
2087 if (debug
& D_ROUTER
) {
2088 logmsg(LOG_DEBUG
, "router_create(%s, %s, %u)\n", pi
->pi_name
,
2089 inet_ntop(AF_INET6
, (void *)&addr
,
2090 abuf
, sizeof (abuf
)), lifetime
);
2093 dr
= (struct router
*)calloc(sizeof (struct router
), 1);
2095 logmsg(LOG_ERR
, "router_create: out of memory\n");
2098 dr
->dr_address
= addr
;
2099 dr
->dr_lifetime
= lifetime
;
2100 router_insert(pi
, dr
);
2101 if (dr
->dr_lifetime
!= 0)
2106 /* Insert in linked list */
2108 router_insert(struct phyint
*pi
, struct router
*dr
)
2110 dr
->dr_next
= pi
->pi_router_list
;
2112 if (pi
->pi_router_list
!= NULL
)
2113 pi
->pi_router_list
->dr_prev
= dr
;
2114 pi
->pi_router_list
= dr
;
2115 dr
->dr_physical
= pi
;
2119 * Delete (unlink and free).
2120 * Handles delete of things that have not yet been inserted in the list
2121 * i.e. dr_physical is NULL.
2124 router_delete(struct router
*dr
)
2127 char abuf
[INET6_ADDRSTRLEN
];
2129 if (debug
& D_ROUTER
) {
2130 logmsg(LOG_DEBUG
, "router_delete(%s, %s, %u)\n",
2131 dr
->dr_physical
->pi_name
,
2132 inet_ntop(AF_INET6
, (void *)&dr
->dr_address
,
2133 abuf
, sizeof (abuf
)), dr
->dr_lifetime
);
2135 pi
= dr
->dr_physical
;
2136 if (dr
->dr_inkernel
&& (pi
->pi_kernel_state
& PI_PRESENT
))
2137 router_delete_k(dr
);
2139 if (dr
->dr_prev
== NULL
) {
2141 pi
->pi_router_list
= dr
->dr_next
;
2143 dr
->dr_prev
->dr_next
= dr
->dr_next
;
2145 if (dr
->dr_next
!= NULL
)
2146 dr
->dr_next
->dr_prev
= dr
->dr_prev
;
2147 dr
->dr_next
= dr
->dr_prev
= NULL
;
2152 * Update the kernel to match dr_lifetime
2155 router_update_k(struct router
*dr
)
2157 char abuf
[INET6_ADDRSTRLEN
];
2159 if (debug
& D_ROUTER
) {
2160 logmsg(LOG_DEBUG
, "router_update_k(%s, %s, %u)\n",
2161 dr
->dr_physical
->pi_name
,
2162 inet_ntop(AF_INET6
, (void *)&dr
->dr_address
,
2163 abuf
, sizeof (abuf
)), dr
->dr_lifetime
);
2166 if (dr
->dr_lifetime
== 0 && dr
->dr_inkernel
) {
2167 /* Log a message when last router goes away */
2168 if (dr
->dr_physical
->pi_num_k_routers
== 1) {
2170 "Last default router (%s) removed on %s\n",
2171 inet_ntop(AF_INET6
, (void *)&dr
->dr_address
,
2172 abuf
, sizeof (abuf
)), dr
->dr_physical
->pi_name
);
2175 } else if (dr
->dr_lifetime
!= 0 && !dr
->dr_inkernel
)
2180 * Called with the number of millseconds elapsed since the last call.
2181 * Determines if any timeout event has occurred and
2182 * returns the number of milliseconds until the next timeout event.
2183 * Returns TIMER_INFINITY for "never".
2186 router_timer(struct router
*dr
, uint_t elapsed
)
2188 uint_t next
= TIMER_INFINITY
;
2189 char abuf
[INET6_ADDRSTRLEN
];
2191 if (debug
& D_ROUTER
) {
2192 logmsg(LOG_DEBUG
, "router_timer(%s, %s, %u, %d)\n",
2193 dr
->dr_physical
->pi_name
,
2194 inet_ntop(AF_INET6
, (void *)&dr
->dr_address
,
2195 abuf
, sizeof (abuf
)), dr
->dr_lifetime
, elapsed
);
2197 if (dr
->dr_lifetime
<= elapsed
) {
2198 dr
->dr_lifetime
= 0;
2200 dr
->dr_lifetime
-= elapsed
;
2201 if (dr
->dr_lifetime
< next
)
2202 next
= dr
->dr_lifetime
;
2205 if (dr
->dr_lifetime
== 0) {
2206 /* Log a message when last router goes away */
2207 if (dr
->dr_physical
->pi_num_k_routers
== 1) {
2209 "Last default router (%s) timed out on %s\n",
2210 inet_ntop(AF_INET6
, (void *)&dr
->dr_address
,
2211 abuf
, sizeof (abuf
)), dr
->dr_physical
->pi_name
);
2219 * Add a default route to the kernel (unless the lifetime is zero)
2220 * Handles onlink default routes.
2223 router_add_k(struct router
*dr
)
2225 struct phyint
*pi
= dr
->dr_physical
;
2226 char abuf
[INET6_ADDRSTRLEN
];
2229 if (debug
& D_ROUTER
) {
2230 logmsg(LOG_DEBUG
, "router_add_k(%s, %s, %u)\n",
2231 dr
->dr_physical
->pi_name
,
2232 inet_ntop(AF_INET6
, (void *)&dr
->dr_address
,
2233 abuf
, sizeof (abuf
)), dr
->dr_lifetime
);
2236 rta_gateway
->sin6_addr
= dr
->dr_address
;
2238 rta_ifp
->sdl_index
= if_nametoindex(pi
->pi_name
);
2239 if (rta_ifp
->sdl_index
== 0) {
2240 logperror_pi(pi
, "router_add_k: if_nametoindex");
2244 rt_msg
->rtm_flags
= RTF_GATEWAY
;
2245 rt_msg
->rtm_type
= RTM_ADD
;
2246 rt_msg
->rtm_seq
= ++rtmseq
;
2247 rlen
= write(rtsock
, rt_msg
, rt_msg
->rtm_msglen
);
2249 if (errno
!= EEXIST
) {
2250 logperror_pi(pi
, "router_add_k: RTM_ADD");
2253 } else if (rlen
< rt_msg
->rtm_msglen
) {
2254 logmsg(LOG_ERR
, "router_add_k: write to routing socket got "
2255 "only %d for rlen (interface %s)\n", rlen
, pi
->pi_name
);
2258 dr
->dr_inkernel
= _B_TRUE
;
2259 pi
->pi_num_k_routers
++;
2263 * Delete a route from the kernel.
2264 * Handles onlink default routes.
2267 router_delete_k(struct router
*dr
)
2269 struct phyint
*pi
= dr
->dr_physical
;
2270 char abuf
[INET6_ADDRSTRLEN
];
2273 if (debug
& D_ROUTER
) {
2274 logmsg(LOG_DEBUG
, "router_delete_k(%s, %s, %u)\n",
2275 dr
->dr_physical
->pi_name
,
2276 inet_ntop(AF_INET6
, (void *)&dr
->dr_address
,
2277 abuf
, sizeof (abuf
)), dr
->dr_lifetime
);
2280 rta_gateway
->sin6_addr
= dr
->dr_address
;
2282 rta_ifp
->sdl_index
= if_nametoindex(pi
->pi_name
);
2283 if (rta_ifp
->sdl_index
== 0) {
2284 logperror_pi(pi
, "router_delete_k: if_nametoindex");
2288 rt_msg
->rtm_flags
= RTF_GATEWAY
;
2289 rt_msg
->rtm_type
= RTM_DELETE
;
2290 rt_msg
->rtm_seq
= ++rtmseq
;
2291 rlen
= write(rtsock
, rt_msg
, rt_msg
->rtm_msglen
);
2293 if (errno
!= ESRCH
) {
2294 logperror_pi(pi
, "router_delete_k: RTM_DELETE");
2296 } else if (rlen
< rt_msg
->rtm_msglen
) {
2297 logmsg(LOG_ERR
, "router_delete_k: write to routing socket got "
2298 "only %d for rlen (interface %s)\n", rlen
, pi
->pi_name
);
2300 dr
->dr_inkernel
= _B_FALSE
;
2301 pi
->pi_num_k_routers
--;
2305 router_print(struct router
*dr
)
2307 char abuf
[INET6_ADDRSTRLEN
];
2309 logmsg(LOG_DEBUG
, "Router %s on %s inkernel %d lifetime %u\n",
2310 inet_ntop(AF_INET6
, (void *)&dr
->dr_address
, abuf
, sizeof (abuf
)),
2311 dr
->dr_physical
->pi_name
, dr
->dr_inkernel
, dr
->dr_lifetime
);
2315 phyint_print_all(void)
2319 for (pi
= phyints
; pi
!= NULL
; pi
= pi
->pi_next
) {
2325 phyint_cleanup(struct phyint
*pi
)
2328 pi
->pi_kernel_state
= 0;
2330 if (pi
->pi_AdvSendAdvertisements
) {
2331 check_to_advertise(pi
, ADV_OFF
);
2333 check_to_solicit(pi
, SOLICIT_OFF
);
2336 while (pi
->pi_router_list
)
2337 router_delete(pi
->pi_router_list
);
2338 (void) poll_remove(pi
->pi_sock
);
2339 (void) close(pi
->pi_sock
);
2341 pi
->pi_stateless
= pi
->pi_StatelessAddrConf
;
2342 pi
->pi_stateful
= pi
->pi_StatefulAddrConf
;
2343 pi
->pi_ipadm_aobjname
[0] = '\0';
2347 * Sets/removes the ipadm address object name for the given prefix.
2350 prefix_update_ipadm_addrobj(struct prefix
*pr
, boolean_t add
)
2352 struct phyint
*pi
= pr
->pr_physical
;
2356 ipadm_status_t status
;
2359 * If ipadm was used to autoconfigure this interface,
2360 * pi_ipadm_aobjname will contain the address object name
2361 * that is used to identify the addresses. Use the same
2362 * address object name for this prefix.
2364 if (pi
->pi_ipadm_aobjname
[0] == '\0' ||
2365 pr
->pr_name
[0] == '\0' || IN6_IS_ADDR_LINKLOCAL(&pr
->pr_address
) ||
2366 (!(pr
->pr_flags
& IFF_ADDRCONF
) &&
2367 !(pr
->pr_flags
& IFF_DHCPRUNNING
))) {
2370 if ((status
= ipadm_open(&iph
, 0)) != IPADM_SUCCESS
) {
2371 logmsg(LOG_ERR
, "Could not open handle to libipadm: %s\n",
2372 ipadm_status2str(status
));
2375 cp
= strrchr(pr
->pr_name
, ':');
2379 status
= ipadm_add_aobjname(iph
, pi
->pi_name
, AF_INET6
,
2380 pi
->pi_ipadm_aobjname
, IPADM_ADDR_IPV6_ADDRCONF
, lnum
);
2382 status
= ipadm_delete_aobjname(iph
, pi
->pi_name
, AF_INET6
,
2383 pi
->pi_ipadm_aobjname
, IPADM_ADDR_IPV6_ADDRCONF
, lnum
);
2385 /* Ignore the error if the ipmgmtd daemon is not running */
2386 if (status
!= IPADM_SUCCESS
&& status
!= IPADM_IPC_ERROR
) {
2387 logmsg(LOG_ERR
, "ipadm error in %s '%s' : %s\n",
2388 (add
? "adding" : "deleting"), pi
->pi_ipadm_aobjname
,
2389 ipadm_status2str(status
));