dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.lib / in.ndpd / tables.c
blob574b408c210a4533aff82b23adc182afc20aa1c8
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include "defs.h"
27 #include "tables.h"
29 #include <time.h>
30 #include <assert.h>
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,
44 int bits);
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 */
58 /* 1 week in ms */
59 #define NDP_PREFIX_DEFAULT_LIFETIME (7*24*60*60*1000)
60 struct phyint *
61 phyint_lookup(char *name)
63 struct phyint *pi;
65 if (debug & D_PHYINT)
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)
70 break;
72 return (pi);
75 struct phyint *
76 phyint_lookup_on_index(uint_t ifindex)
78 struct phyint *pi;
80 if (debug & D_PHYINT)
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)
85 break;
87 return (pi);
90 struct phyint *
91 phyint_create(char *name)
93 struct phyint *pi;
94 int i;
96 if (debug & D_PHYINT)
97 logmsg(LOG_DEBUG, "phyint_create(%s)\n", name);
99 pi = (struct phyint *)calloc(sizeof (struct phyint), 1);
100 if (pi == NULL) {
101 logmsg(LOG_ERR, "phyint_create: out of memory\n");
102 return (NULL);
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,
122 * per RFC3041.
124 if (pi->pi_TmpMaxDesyncFactor != 0) {
125 time_t seed = time(NULL);
126 srand((uint_t)seed);
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;
133 pi->pi_sock = -1;
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) {
139 free(pi);
140 return (NULL);
142 phyint_insert(pi);
143 if (pi->pi_sock != -1) {
144 if (poll_add(pi->pi_sock) == -1) {
145 phyint_delete(pi);
146 return (NULL);
149 return (pi);
152 /* Insert in linked list */
153 static void
154 phyint_insert(struct phyint *pi)
156 /* Insert in list */
157 pi->pi_next = phyints;
158 pi->pi_prev = NULL;
159 if (phyints)
160 phyints->pi_prev = pi;
161 phyints = pi;
162 num_of_phyints++;
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;
174 struct lifreq lifr;
175 int fd;
176 int save_errno;
177 boolean_t newsock;
178 uint_t ttl;
179 struct sockaddr_in6 *sin6;
181 if (debug & D_PHYINT)
182 logmsg(LOG_DEBUG, "phyint_init_from_k(%s)\n", pi->pi_name);
184 start_over:
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");
190 return (-1);
192 newsock = _B_TRUE;
193 } else {
194 newsock = _B_FALSE;
196 fd = pi->pi_sock;
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) {
202 if (newsock) {
203 (void) close(pi->pi_sock);
204 pi->pi_sock = -1;
206 if (debug & D_PHYINT) {
207 logmsg(LOG_DEBUG, "phyint_init_from_k(%s): "
208 "not exist\n", pi->pi_name);
210 return (0);
212 logperror_pi(pi, "phyint_init_from_k: SIOCGLIFINDEX");
213 goto error;
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
220 * quite frequently.
223 phyint_cleanup(pi);
224 goto start_over;
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)");
231 goto error;
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)) {
240 if (newsock) {
241 (void) close(pi->pi_sock);
242 pi->pi_sock = -1;
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);
249 return (0);
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)");
255 goto error;
257 pi->pi_mtu = lifr.lifr_mtu;
259 if (ioctl(fd, SIOCGLIFADDR, (char *)&lifr) < 0) {
260 logperror_pi(pi, "phyint_init_from_k: SIOCGLIFADDR");
261 goto error;
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");
269 goto error;
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",
275 pi->pi_name);
276 goto error;
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");
289 goto error;
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;
296 } else {
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;
302 } else {
303 pi->pi_dst_token = in6addr_any;
306 if (newsock) {
307 icmp6_filter_t filter;
308 int on = 1;
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 "
322 "IPV6_BOUND_IF");
323 goto error;
326 ttl = IPV6_MAX_HOPS;
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");
331 goto error;
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");
338 goto error;
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.
352 save_errno = errno;
353 (void) strlcpy(lifr.lifr_name, pi->pi_name, LIFNAMSIZ);
354 if (ioctl(fd, SIOCGLIFGROUPNAME, &lifr) == -1 ||
355 lifr.lifr_groupname[0] == '\0') {
356 errno = save_errno;
357 logperror_pi(pi, "phyint_init_from_k: "
358 "setsockopt IPV6_JOIN_GROUP");
360 goto error;
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 "
376 "ICMP6_FILTER");
377 goto error;
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");
385 goto error;
387 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVRTHDR,
388 (char *)&on, sizeof (on)) < 0) {
389 logperror_pi(pi, "phyint_init_from_k: setsockopt "
390 "IPV6_RECVRTHDR");
391 goto error;
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.
404 save_errno = errno;
405 (void) strlcpy(lifr.lifr_name, pi->pi_name, LIFNAMSIZ);
406 if (ioctl(fd, SIOCGLIFGROUPNAME, &lifr) == -1 ||
407 lifr.lifr_groupname[0] == '\0') {
408 errno = save_errno;
409 logperror_pi(pi, "phyint_init_from_k: "
410 "setsockopt IPV6_JOIN_GROUP");
412 goto error;
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");
428 goto error;
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");
435 goto error;
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");
450 goto error;
452 if (debug & D_PHYINT) {
453 logmsg(LOG_DEBUG, "phyint_init_from_k(%s): done\n",
454 pi->pi_name);
456 return (0);
458 error:
459 /* Pretend the interface does not exist in the kernel */
460 pi->pi_kernel_state &= ~PI_PRESENT;
461 if (newsock) {
462 (void) close(pi->pi_sock);
463 pi->pi_sock = -1;
465 return (-1);
469 * Delete (unlink and free).
470 * Handles delete of things that have not yet been inserted in the list.
472 void
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");
494 pi->pi_sock = -1;
497 if (pi->pi_prev == NULL) {
498 if (phyints == pi)
499 phyints = pi->pi_next;
500 } else {
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;
506 free(pi);
507 num_of_phyints--;
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".
517 uint_t
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) "
533 "state %d -> %d\n",
534 pi->pi_name, (int)old_state,
535 (int)pi->pi_adv_state);
538 } else {
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) "
549 "state %d -> %d\n",
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);
568 return (next);
571 static void
572 phyint_print(struct phyint *pi)
574 struct prefix *pr;
575 struct adv_prefix *adv_pr;
576 struct router *dr;
577 char abuf[INET6_ADDRSTRLEN];
579 logmsg(LOG_DEBUG, "Phyint %s index %d state %x, kernel %x, "
580 "num routers %d\n",
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) {
610 /* Solicit state */
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);
613 } else {
614 /* Advertise state */
615 logmsg(LOG_DEBUG, "\tADVERT: time_left %d state %d count %d "
616 "since last %d\n",
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)
622 prefix_print(pr);
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)
630 router_print(dr);
632 logmsg(LOG_DEBUG, "\n");
637 * Store the LLA for the phyint `pi' `lifrp'. Returns 0 on success, or
638 * -1 on failure.
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)) {
651 return (-1);
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");
667 return (-1);
669 return (0);
673 * Randomize pi->pi_ReachableTime.
674 * Done periodically when there are no RAs and at a maximum frequency when
675 * RA's arrive.
676 * Assumes that caller has determined that it is time to generate
677 * a new random ReachableTime.
679 void
680 phyint_reach_random(struct phyint *pi, boolean_t set_needed)
682 struct lifreq lifr;
684 pi->pi_ReachableTime = GET_RANDOM(
685 (int)(ND_MIN_RANDOM_FACTOR * pi->pi_BaseReachableTime),
686 (int)(ND_MAX_RANDOM_FACTOR * pi->pi_BaseReachableTime));
687 if (set_needed) {
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) {
692 logperror_pi(pi,
693 "phyint_reach_random: SIOCSLIFLNKINFO");
694 return;
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
706 * bit is set.
708 * Called by tmptoken_create().
710 * Return _B_TRUE if token is valid (no match), _B_FALSE if not.
712 static boolean_t
713 tmptoken_isvalid(struct in6_addr *token)
715 struct phyint *pi;
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, \
720 0, 0, 0, 0, \
721 0xfd, 0xff, 0xff, 0xff, \
722 0xff, 0xff, 0xff, 0x80 } } };
724 if (IN6_IS_ADDR_UNSPECIFIED(token))
725 return (_B_FALSE);
727 if (token->s6_addr[8] & 0x2)
728 return (_B_FALSE);
730 (void) memcpy(&mask, token, sizeof (mask));
731 mask._S6_un._S6_u32[3] = 0;
732 if (IN6_ARE_ADDR_EQUAL(&isatap, token))
733 return (_B_FALSE);
735 mask._S6_un._S6_u32[3] = token->_S6_un._S6_u32[3] & 0xffffff80;
736 if (IN6_ARE_ADDR_EQUAL(&anycast, token))
737 return (_B_FALSE);
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))
743 return (_B_FALSE);
746 /* none of our tests failed, must be a good one! */
747 return (_B_TRUE);
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.
758 boolean_t
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");
768 goto no_token;
771 bzero((char *)&token, sizeof (token));
772 do {
773 if (read(fd, (void *)tokenp, TMP_TOKEN_BYTES) == -1) {
774 perror("read /dev/urandom");
775 (void) close(fd);
776 goto no_token;
780 * Assume EUI-64 formatting, and thus 64-bit
781 * token len; need to clear global bit.
783 token.s6_addr[8] &= 0xfd;
785 i++;
787 } while (!tmptoken_isvalid(&token) && i < max_tries);
789 (void) close(fd);
791 if (i == max_tries) {
792 no_token:
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;
797 return (_B_FALSE);
800 pi->pi_tmp_token = token;
802 if (debug & D_TMP)
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);
812 return (_B_TRUE);
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
823 * addr.
825 void
826 tmptoken_delete(struct phyint *pi)
828 struct prefix *pr;
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,
834 TMP_TOKEN_BITS))) {
835 continue;
837 pr->pr_PreferredLifetime = 0;
838 pr->pr_state |= PR_DEPRECATED;
839 prefix_update_k(pr);
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".
851 uint_t
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;
858 if (debug & D_TMP) {
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)
888 continue;
890 newpr = prefix_create(pi, pr->pr_prefix, pr->pr_prefix_len,
891 IFF_TEMPORARY);
892 if (newpr == NULL) {
893 char pbuf[INET6_ADDRSTRLEN];
894 char tbuf[INET6_ADDRSTRLEN];
895 (void) inet_ntop(AF_INET6, &pr->pr_prefix, pbuf,
896 sizeof (pbuf));
897 (void) inet_ntop(AF_INET6, &pi->pi_tmp_token, tbuf,
898 sizeof (tbuf));
899 logmsg(LOG_ERR, "can't create new tmp addr "
900 "(%s, %s, %s)\n", pi->pi_name, pbuf, tbuf);
901 continue;
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
909 * remaining.
911 * The "from" param is only used for messages; pass in
912 * ::0 for that.
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,
933 sizeof (pbuf));
934 (void) inet_ntop(AF_INET6, &pi->pi_tmp_token, tbuf,
935 sizeof (tbuf));
936 logmsg(LOG_ERR, "can't create new tmp addr "
937 "(%s, %s, %s)\n", pi->pi_name, pbuf, tbuf);
938 continue;
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
957 * values of tlen.
959 boolean_t
960 token_equal(struct in6_addr t1, struct in6_addr t2, int tlen)
962 uchar_t mask;
963 int j, abytes, tbytes, tbits;
965 if (tlen < 0 || tlen > IPV6_ABITS)
966 return (_B_FALSE);
968 abytes = IPV6_ABITS >> 3;
969 tbytes = tlen >> 3;
970 tbits = tlen & 7;
972 for (j = abytes - 1; j >= abytes - tbytes; j--)
973 if (t1.s6_addr[j] != t2.s6_addr[j])
974 return (_B_FALSE);
976 if (tbits == 0)
977 return (_B_TRUE);
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))
982 return (_B_FALSE);
984 return (_B_TRUE);
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)
994 struct prefix *pr;
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))
1006 return (pr);
1008 return (NULL);
1012 * Compare two prefixes that have the same prefix length.
1013 * Fails if the prefix length is unreasonable.
1015 boolean_t
1016 prefix_equal(struct in6_addr p1, struct in6_addr p2, int plen)
1018 uchar_t mask;
1019 int j, pbytes, pbits;
1021 if (plen < 0 || plen > IPV6_ABITS)
1022 return (_B_FALSE);
1024 pbytes = plen >> 3;
1025 pbits = plen & 7;
1027 for (j = 0; j < pbytes; j++)
1028 if (p1.s6_addr[j] != p2.s6_addr[j])
1029 return (_B_FALSE);
1031 if (pbits == 0)
1032 return (_B_TRUE);
1034 /* Make the N leftmost bits one */
1035 mask = 0xff << (8 - pbits);
1036 if ((p1.s6_addr[j] & mask) != (p2.s6_addr[j] & mask))
1037 return (_B_FALSE);
1039 return (_B_TRUE);
1043 * Set a prefix from an address and a prefix length.
1044 * Force all the bits after the prefix length to be zero.
1046 void
1047 prefix_set(struct in6_addr *prefix, struct in6_addr addr, int prefix_len)
1049 uchar_t mask;
1050 int j;
1052 if (prefix_len < 0 || prefix_len > IPV6_ABITS)
1053 return;
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.
1068 struct prefix *
1069 prefix_lookup_name(struct phyint *pi, char *name)
1071 struct prefix *pr;
1073 if (debug & D_PREFIX) {
1074 logmsg(LOG_DEBUG, "prefix_lookup_name(%s, %s)\n",
1075 pi->pi_name, name);
1077 if (name[0] == '\0')
1078 return (NULL);
1080 for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) {
1081 if (strcmp(name, pr->pr_name) == 0)
1082 return (pr);
1084 return (NULL);
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
1092 struct prefix *
1093 prefix_lookup_addr_match(struct prefix *pr)
1095 char abuf[INET6_ADDRSTRLEN];
1096 struct phyint *pi;
1097 struct prefix *otherpr = NULL;
1098 struct in6_addr prefix;
1099 int prefixlen;
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);
1110 if (otherpr == pr)
1111 continue;
1112 if (otherpr != NULL && (otherpr->pr_state & PR_AUTO) &&
1113 IN6_ARE_ADDR_EQUAL(&pr->pr_address,
1114 &otherpr->pr_address))
1115 return (otherpr);
1117 return (NULL);
1121 * Initialize a new prefix without setting lifetimes etc.
1123 struct prefix *
1124 prefix_create(struct phyint *pi, struct in6_addr prefix, int prefixlen,
1125 uint64_t flags)
1127 struct prefix *pr;
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);
1136 if (pr == NULL) {
1137 logmsg(LOG_ERR, "prefix_create: out of memory\n");
1138 return (NULL);
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);
1152 return (pr);
1156 * Create a new named prefix. Caller should use prefix_init_from_k
1157 * to initialize the content.
1159 struct prefix *
1160 prefix_create_name(struct phyint *pi, char *name)
1162 struct prefix *pr;
1164 if (debug & D_PREFIX) {
1165 logmsg(LOG_DEBUG, "prefix_create_name(%s, %s)\n",
1166 pi->pi_name, name);
1168 pr = (struct prefix *)calloc(sizeof (struct prefix), 1);
1169 if (pr == NULL) {
1170 logmsg(LOG_ERR, "prefix_create_name: out of memory\n");
1171 return (NULL);
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);
1176 return (pr);
1179 /* Insert in linked list */
1180 static void
1181 prefix_insert(struct phyint *pi, struct prefix *pr)
1183 pr->pr_next = pi->pi_prefix_list;
1184 pr->pr_prev = NULL;
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)
1202 struct lifreq lifr;
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)");
1210 goto error;
1212 if (lifr.lifr_addr.ss_family != AF_INET6) {
1213 logmsg(LOG_ERR, "ignoring interface %s: not AF_INET6\n",
1214 pr->pr_name);
1215 goto error;
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)");
1222 goto error;
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;
1231 struct prefix *pr2;
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)) {
1237 if (debug & D_DHCP)
1238 logmsg(LOG_DEBUG, "prefix_init_from_k: "
1239 "ignoring DHCP %s not ready\n",
1240 pr->pr_name);
1241 return (0);
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;
1257 break;
1260 if (pr2 == NULL) {
1261 if (debug & D_DHCP)
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);
1266 } else {
1267 if (debug & D_DHCP)
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);
1280 } else {
1281 if (ioctl(sock, SIOCGLIFSUBNET, (char *)&lifr) < 0) {
1282 logperror_pr(pr,
1283 "prefix_init_from_k: ioctl (get subnet)");
1284 goto error;
1286 if (lifr.lifr_subnet.ss_family != AF_INET6) {
1287 logmsg(LOG_ERR,
1288 "ignoring interface %s: not AF_INET6\n",
1289 pr->pr_name);
1290 goto error;
1293 * Guard against the prefix having non-zero bits after the
1294 * prefix len bits.
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 "
1307 "(%s/%u)\n",
1308 pr->pr_name,
1309 inet_ntop(AF_INET6, (void *)&pr->pr_address,
1310 abuf, sizeof (abuf)), pr->pr_prefix_len);
1311 goto error;
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) {
1328 pr->pr_prefix_len =
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';
1348 return (0);
1350 error:
1351 /* Pretend that the prefix does not exist in the kernel */
1352 pr->pr_kernel_state = 0;
1353 pr->pr_name[0] = '\0';
1354 return (-1);
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.
1364 void
1365 prefix_delete(struct prefix *pr)
1367 struct phyint *pi;
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) {
1384 if (pi != NULL)
1385 pi->pi_prefix_list = pr->pr_next;
1386 } else {
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;
1393 free(pr);
1397 * Toggle one or more IFF_ flags for a prefix. Turn on 'onflags' and
1398 * turn off 'offflags'.
1400 static int
1401 prefix_modify_flags(struct prefix *pr, uint64_t onflags, uint64_t offflags)
1403 struct lifreq lifr;
1404 struct phyint *pi = pr->pr_physical;
1405 uint64_t old_flags;
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,
1412 pr->pr_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);
1423 return (-1);
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);
1435 return (-1);
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);
1449 return (-1);
1451 return (0);
1455 * Update the subnet mask for this interface under DHCPv6 control.
1457 void
1458 prefix_update_dhcp(struct prefix *pr)
1460 struct lifreq lifr;
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.
1483 void
1484 prefix_update_k(struct prefix *pr)
1486 struct lifreq lifr;
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,
1498 sizeof (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)
1507 return;
1509 if (pr->pr_kernel_state == 0) {
1510 uint64_t onflags;
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,
1523 sizeof (buf1)),
1524 prefix_print_state(pr->pr_state, buf2,
1525 sizeof (buf2)));
1526 return;
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");
1535 return;
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",
1542 pr->pr_name);
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
1550 * flags yet.
1552 onflags = IFF_ADDRCONF;
1553 if (pr->pr_flags & IFF_TEMPORARY)
1554 onflags |= IFF_TEMPORARY;
1555 if (prefix_modify_flags(pr, onflags, 0) == -1)
1556 return;
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)
1561 return;
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",
1568 pr->pr_name);
1572 * Assumes that only the PR_STATIC link-local matches
1573 * the pi_name
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);
1579 return;
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 &&
1585 errno != ENXIO) {
1586 logperror_pr(pr, "prefix_update_k: SIOCLIFREMOVEIF");
1588 pr->pr_kernel_state = 0;
1589 pr->pr_name[0] = '\0';
1590 return;
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.
1596 * Turn on IFF_UP.
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 "
1607 "for PR_AUTO on\n",
1608 pr->pr_name,
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");
1614 return;
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;
1624 } else {
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");
1636 return;
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) {
1645 int i;
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) {
1664 logperror_pr(pr,
1665 "prefix_update_k: SIOCSLIFDSTADDR");
1666 return;
1669 if (prefix_modify_flags(pr, IFF_UP, IFF_NOLOCAL) == -1)
1670 return;
1671 pr->pr_kernel_state |= PR_AUTO;
1672 if (pr->pr_state & PR_ONLINK)
1673 pr->pr_kernel_state |= PR_ONLINK;
1674 else
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)
1680 return;
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");
1695 return;
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)
1704 return;
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)
1710 return;
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");
1731 return;
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)
1741 return;
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");
1762 return;
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".
1774 uint_t
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",
1783 pr->pr_name,
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)
1792 return (next);
1794 if (pr->pr_AutonomousFlag &&
1795 (pr->pr_PreferredLifetime != PREFIX_INFINITY)) {
1796 if (pr->pr_PreferredLifetime <= elapsed) {
1797 pr->pr_PreferredLifetime = 0;
1798 } else {
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;
1808 } else {
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;
1818 } else {
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;
1829 if (debug & D_TMP)
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];
1844 logmsg(LOG_WARNING,
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);
1852 return (next);
1855 static char *
1856 prefix_print_state(int state, char *buf, int buflen)
1858 char *cp;
1859 int cplen = buflen;
1861 cp = buf;
1862 cp[0] = '\0';
1864 if (state & PR_ONLINK) {
1865 if (strlcat(cp, "ONLINK ", cplen) >= cplen)
1866 return (buf);
1867 cp += strlen(cp);
1868 cplen = buflen - (cp - buf);
1870 if (state & PR_AUTO) {
1871 if (strlcat(cp, "AUTO ", cplen) >= cplen)
1872 return (buf);
1873 cp += strlen(cp);
1874 cplen = buflen - (cp - buf);
1876 if (state & PR_DEPRECATED) {
1877 if (strlcat(cp, "DEPRECATED ", cplen) >= cplen)
1878 return (buf);
1879 cp += strlen(cp);
1880 cplen = buflen - (cp - buf);
1882 if (state & PR_STATIC) {
1883 if (strlcat(cp, "STATIC ", cplen) >= cplen)
1884 return (buf);
1885 cp += strlen(cp);
1886 cplen = buflen - (cp - buf);
1888 return (buf);
1891 static void
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)),
1900 pr->pr_prefix_len,
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
1916 * prefix length.
1917 * Assumes that the bits after prefixlen might not be zero.
1919 struct adv_prefix *
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))
1935 return (adv_pr);
1937 return (NULL);
1941 * Initialize a new advertisement prefix.
1943 struct adv_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");
1957 return (NULL);
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);
1966 return (adv_pr);
1969 /* Insert in linked list */
1970 static void
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.
1986 static void
1987 adv_prefix_delete(struct adv_prefix *adv_pr)
1989 struct phyint *pi;
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) {
2001 if (pi != NULL)
2002 pi->pi_adv_prefix_list = adv_pr->adv_pr_next;
2003 } else {
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;
2009 free(adv_pr);
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".
2018 uint_t
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,
2029 elapsed);
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;
2036 else
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 -=
2042 seconds_elapsed;
2043 } else {
2044 adv_pr->adv_pr_AdvPreferredExpiration = 0;
2047 return (TIMER_INFINITY);
2050 static void
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 */
2057 struct router *
2058 router_lookup(struct phyint *pi, struct in6_addr addr)
2060 struct router *dr;
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)
2072 return (dr);
2074 return (NULL);
2078 * Create a default router entry.
2079 * The lifetime parameter is in seconds.
2081 struct router *
2082 router_create(struct phyint *pi, struct in6_addr addr, uint_t lifetime)
2084 struct router *dr;
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);
2094 if (dr == NULL) {
2095 logmsg(LOG_ERR, "router_create: out of memory\n");
2096 return (NULL);
2098 dr->dr_address = addr;
2099 dr->dr_lifetime = lifetime;
2100 router_insert(pi, dr);
2101 if (dr->dr_lifetime != 0)
2102 router_add_k(dr);
2103 return (dr);
2106 /* Insert in linked list */
2107 static void
2108 router_insert(struct phyint *pi, struct router *dr)
2110 dr->dr_next = pi->pi_router_list;
2111 dr->dr_prev = NULL;
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.
2123 static void
2124 router_delete(struct router *dr)
2126 struct phyint *pi;
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) {
2140 if (pi != NULL)
2141 pi->pi_router_list = dr->dr_next;
2142 } else {
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;
2148 free(dr);
2152 * Update the kernel to match dr_lifetime
2154 void
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) {
2169 logmsg(LOG_WARNING,
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);
2174 router_delete(dr);
2175 } else if (dr->dr_lifetime != 0 && !dr->dr_inkernel)
2176 router_add_k(dr);
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".
2185 uint_t
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;
2199 } else {
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) {
2208 logmsg(LOG_WARNING,
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);
2213 router_delete(dr);
2215 return (next);
2219 * Add a default route to the kernel (unless the lifetime is zero)
2220 * Handles onlink default routes.
2222 static void
2223 router_add_k(struct router *dr)
2225 struct phyint *pi = dr->dr_physical;
2226 char abuf[INET6_ADDRSTRLEN];
2227 int rlen;
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");
2241 return;
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);
2248 if (rlen < 0) {
2249 if (errno != EEXIST) {
2250 logperror_pi(pi, "router_add_k: RTM_ADD");
2251 return;
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);
2256 return;
2258 dr->dr_inkernel = _B_TRUE;
2259 pi->pi_num_k_routers++;
2263 * Delete a route from the kernel.
2264 * Handles onlink default routes.
2266 static void
2267 router_delete_k(struct router *dr)
2269 struct phyint *pi = dr->dr_physical;
2270 char abuf[INET6_ADDRSTRLEN];
2271 int rlen;
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");
2285 return;
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);
2292 if (rlen < 0) {
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--;
2304 static void
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);
2314 void
2315 phyint_print_all(void)
2317 struct phyint *pi;
2319 for (pi = phyints; pi != NULL; pi = pi->pi_next) {
2320 phyint_print(pi);
2324 void
2325 phyint_cleanup(struct phyint *pi)
2327 pi->pi_state = 0;
2328 pi->pi_kernel_state = 0;
2330 if (pi->pi_AdvSendAdvertisements) {
2331 check_to_advertise(pi, ADV_OFF);
2332 } else {
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);
2340 pi->pi_sock = -1;
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.
2349 void
2350 prefix_update_ipadm_addrobj(struct prefix *pr, boolean_t add)
2352 struct phyint *pi = pr->pr_physical;
2353 int lnum = 0;
2354 char *cp;
2355 ipadm_handle_t iph;
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))) {
2368 return;
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));
2373 return;
2375 cp = strrchr(pr->pr_name, ':');
2376 if (cp != NULL)
2377 lnum = atoi(++cp);
2378 if (add) {
2379 status = ipadm_add_aobjname(iph, pi->pi_name, AF_INET6,
2380 pi->pi_ipadm_aobjname, IPADM_ADDR_IPV6_ADDRCONF, lnum);
2381 } else {
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));
2391 ipadm_close(iph);