Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet6/in6_ifattach.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet6/in6_ifattach.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.61 retrieving revision 1.61.12.3 diff -u -p -r1.61 -r1.61.12.3 --- src/sys/netinet6/in6_ifattach.c 2004/04/20 17:12:03 1.61 +++ src/sys/netinet6/in6_ifattach.c 2007/02/26 09:11:49 1.61.12.3 @@ -1,4 +1,4 @@ -/* $NetBSD: in6_ifattach.c,v 1.61 2004/04/20 17:12:03 itojun Exp $ */ +/* $NetBSD: in6_ifattach.c,v 1.61.12.3 2007/02/26 09:11:49 yamt Exp $ */ /* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $ */ /* @@ -31,7 +31,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.61 2004/04/20 17:12:03 itojun Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.61.12.3 2007/02/26 09:11:49 yamt Exp $"); #include #include @@ -55,6 +55,7 @@ __KERNEL_RCSID(0, "$NetBSD: in6_ifattach #include #include #include +#include #include @@ -62,8 +63,14 @@ unsigned long in6_maxmtu = 0; int ip6_auto_linklocal = 1; /* enable by default */ +struct callout in6_tmpaddrtimer_ch = CALLOUT_INITIALIZER; + + +#if 0 +static int get_hostid_ifid __P((struct ifnet *, struct in6_addr *)); +#endif static int get_rand_ifid __P((struct ifnet *, struct in6_addr *)); -static int get_hw_ifid __P((struct ifnet *, struct in6_addr *)); +static int generate_tmp_ifid __P((u_int8_t *, const u_int8_t *, u_int8_t *)); static int get_ifid __P((struct ifnet *, struct ifnet *, struct in6_addr *)); static int in6_ifattach_linklocal __P((struct ifnet *, struct ifnet *)); static int in6_ifattach_loopback __P((struct ifnet *)); @@ -79,6 +86,51 @@ static int in6_ifattach_loopback __P((st #define IFID_LOCAL(in6) (!EUI64_LOCAL(in6)) #define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6)) +#define GEN_TEMPID_RETRY_MAX 5 + +#if 0 +/* + * Generate a last-resort interface identifier from hostid. + * works only for certain architectures (like sparc). + * also, using hostid itself may constitute a privacy threat, much worse + * than MAC addresses (hostids are used for software licensing). + * maybe we should use MD5(hostid) instead. + */ +static int +get_hostid_ifid(ifp, in6) + struct ifnet *ifp; + struct in6_addr *in6; /* upper 64bits are preserved */ +{ + int off, len; + static const uint8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + static const uint8_t allone[8] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + if (!hostid) + return -1; + + /* get up to 8 bytes from the hostid field - should we get */ + len = (sizeof(hostid) > 8) ? 8 : sizeof(hostid); + off = sizeof(*in6) - len; + memcpy(&in6->s6_addr[off], &hostid, len); + + /* make sure we do not return anything bogus */ + if (memcmp(&in6->s6_addr[8], allzero, sizeof(allzero))) + return -1; + if (memcmp(&in6->s6_addr[8], allone, sizeof(allone))) + return -1; + + /* make sure to set "u" bit to local, and "g" bit to individual. */ + in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ + in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */ + + /* convert EUI64 into IPv6 interface identifier */ + EUI64_TO_IFID(in6); + + return 0; +} +#endif + /* * Generate a last-resort interface identifier, when the machine has no * IEEE802/EUI64 address sources. @@ -87,9 +139,8 @@ static int in6_ifattach_loopback __P((st * We currently use MD5(hostname) for it. */ static int -get_rand_ifid(ifp, in6) - struct ifnet *ifp; - struct in6_addr *in6; /* upper 64bits are preserved */ +get_rand_ifid(struct ifnet *ifp, + struct in6_addr *in6) /* upper 64bits are preserved */ { MD5_CTX ctxt; u_int8_t digest[16]; @@ -101,13 +152,13 @@ get_rand_ifid(ifp, in6) #endif /* generate 8 bytes of pseudo-random value. */ - bzero(&ctxt, sizeof(ctxt)); + memset(&ctxt, 0, sizeof(ctxt)); MD5Init(&ctxt); MD5Update(&ctxt, (u_char *)hostname, hostnamelen); MD5Final(digest, &ctxt); /* assumes sizeof(digest) > sizeof(ifid) */ - bcopy(digest, &in6->s6_addr[8], 8); + memcpy(&in6->s6_addr[8], digest, 8); /* make sure to set "u" bit to local, and "g" bit to individual. */ in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */ @@ -119,12 +170,158 @@ get_rand_ifid(ifp, in6) return 0; } +static int +generate_tmp_ifid(seed0, seed1, ret) + u_int8_t *seed0, *ret; + const u_int8_t *seed1; +{ + MD5_CTX ctxt; + u_int8_t seed[16], digest[16], nullbuf[8]; + u_int32_t val32; + /* + * interface ID for subnet anycast addresses. + * XXX: we assume the unicast address range that requires IDs + * in EUI-64 format. + */ + static const uint8_t anycast_id[8] = { 0xfd, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80 }; + static const uint8_t isatap_id[4] = { 0x00, 0x00, 0x5e, 0xfe }; + int badid, retry = 0; + + /* If there's no hisotry, start with a random seed. */ + memset(nullbuf, 0, sizeof(nullbuf)); + if (memcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) { + int i; + + for (i = 0; i < 2; i++) { + val32 = arc4random(); + memcpy(seed + sizeof(val32) * i, &val32, sizeof(val32)); + } + } else + memcpy(seed, seed0, 8); + + /* copy the right-most 64-bits of the given address */ + /* XXX assumption on the size of IFID */ + memcpy(&seed[8], seed1, 8); + + again: + /* for debugging purposes only */ +#if 0 + { + int i; + + printf("generate_tmp_ifid: new randomized ID from: "); + for (i = 0; i < 16; i++) + printf("%02x", seed[i]); + printf(" "); + } +#endif + + /* generate 16 bytes of pseudo-random value. */ + memset(&ctxt, 0, sizeof(ctxt)); + MD5Init(&ctxt); + MD5Update(&ctxt, seed, sizeof(seed)); + MD5Final(digest, &ctxt); + + /* + * draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (3) + * Take the left-most 64-bits of the MD5 digest and set bit 6 (the + * left-most bit is numbered 0) to zero. + */ + memcpy(ret, digest, 8); + ret[0] &= ~EUI64_UBIT; + + /* + * Reject inappropriate identifiers according to + * draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (4) + * At this moment, we reject following cases: + * - all 0 identifier + * - identifiers that conflict with reserved subnet anycast addresses, + * which are defined in RFC 2526. + * - identifiers that conflict with ISATAP addresses + * - identifiers used in our own addresses + */ + badid = 0; + if (memcmp(nullbuf, ret, sizeof(nullbuf)) == 0) + badid = 1; + else if (memcmp(anycast_id, ret, 7) == 0 && + (anycast_id[7] & ret[7]) == anycast_id[7]) { + badid = 1; + } else if (memcmp(isatap_id, ret, sizeof(isatap_id)) == 0) + badid = 1; + else { + struct in6_ifaddr *ia; + + for (ia = in6_ifaddr; ia; ia = ia->ia_next) { + if (!memcmp(&ia->ia_addr.sin6_addr.s6_addr[8], + ret, 8)) { + badid = 1; + break; + } + } + } + + /* + * In the event that an unacceptable identifier has been generated, + * restart the process, using the right-most 64 bits of the MD5 digest + * obtained in place of the history value. + */ + if (badid) { + /* for debugging purposes only */ +#if 0 + { + int i; + + printf("unacceptable random ID: "); + for (i = 0; i < 16; i++) + printf("%02x", digest[i]); + printf("\n"); + } +#endif + + if (++retry < GEN_TEMPID_RETRY_MAX) { + memcpy(seed, &digest[8], 8); + goto again; + } else { + /* + * We're so unlucky. Give up for now, and return + * all 0 IDs to tell the caller not to make a + * temporary address. + */ + nd6log((LOG_NOTICE, + "generate_tmp_ifid: never found a good ID\n")); + memset(ret, 0, 8); + } + } + + /* + * draft-ietf-ipngwg-temp-addresses-v2-00.txt 3.2.1. (6) + * Take the rightmost 64-bits of the MD5 digest and save them in + * stable storage as the history value to be used in the next + * iteration of the algorithm. + */ + memcpy(seed0, &digest[8], 8); + + /* for debugging purposes only */ +#if 0 + { + int i; + + printf("to: "); + for (i = 0; i < 16; i++) + printf("%02x", digest[i]); + printf("\n"); + } +#endif + + return 0; +} /* * Get interface identifier for the specified interface. * XXX assumes single sockaddr_dl (AF_LINK address) per an interface */ -static int -get_hw_ifid(ifp, in6) +int +in6_get_hw_ifid(ifp, in6) struct ifnet *ifp; struct in6_addr *in6; /* upper 64bits are preserved */ { @@ -136,10 +333,7 @@ get_hw_ifid(ifp, in6) static u_int8_t allone[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - for (ifa = ifp->if_addrlist.tqh_first; - ifa; - ifa = ifa->ifa_list.tqe_next) - { + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; sdl = (struct sockaddr_dl *)ifa->ifa_addr; @@ -185,14 +379,14 @@ found: * since wildboar configures all-zero MAC on pccard before * card insertion. */ - if (bcmp(addr, allzero, addrlen) == 0) + if (memcmp(addr, allzero, addrlen) == 0) return -1; - if (bcmp(addr, allone, addrlen) == 0) + if (memcmp(addr, allone, addrlen) == 0) return -1; /* make EUI64 address */ if (addrlen == 8) - bcopy(addr, &in6->s6_addr[8], 8); + memcpy(&in6->s6_addr[8], addr, 8); else if (addrlen == 6) { in6->s6_addr[8] = addr[0]; in6->s6_addr[9] = addr[1]; @@ -211,7 +405,7 @@ found: if (!addr[0]) return -1; - bzero(&in6->s6_addr[8], 8); + memset(&in6->s6_addr[8], 0, 8); in6->s6_addr[15] = addr[0]; /* @@ -249,7 +443,7 @@ found: * subnet router anycast */ if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 && - bcmp(&in6->s6_addr[9], allzero, 7) == 0) { + memcmp(&in6->s6_addr[9], allzero, 7) == 0) { return -1; } @@ -270,25 +464,24 @@ get_ifid(ifp0, altifp, in6) struct ifnet *ifp; /* first, try to get it from the interface itself */ - if (get_hw_ifid(ifp0, in6) == 0) { + if (in6_get_hw_ifid(ifp0, in6) == 0) { nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n", if_name(ifp0))); goto success; } /* try secondary EUI64 source. this basically is for ATM PVC */ - if (altifp && get_hw_ifid(altifp, in6) == 0) { + if (altifp && in6_get_hw_ifid(altifp, in6) == 0) { nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n", if_name(ifp0), if_name(altifp))); goto success; } /* next, try to get it from some other hardware interface */ - for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) - { + TAILQ_FOREACH(ifp, &ifnet, if_list) { if (ifp == ifp0) continue; - if (get_hw_ifid(ifp, in6) != 0) + if (in6_get_hw_ifid(ifp, in6) != 0) continue; /* @@ -303,6 +496,16 @@ get_ifid(ifp0, altifp, in6) } } +#if 0 + /* get from hostid - only for certain architectures */ + if (get_hostid_ifid(ifp, in6) == 0) { + nd6log((LOG_DEBUG, + "%s: interface identifier generated by hostid\n", + if_name(ifp0))); + goto success; + } +#endif + /* last resort: get from random number source */ if (get_rand_ifid(ifp, in6) == 0) { nd6log((LOG_DEBUG, @@ -329,13 +532,13 @@ in6_ifattach_linklocal(ifp, altifp) { struct in6_ifaddr *ia; struct in6_aliasreq ifra; - struct nd_prefix pr0; + struct nd_prefixctl pr0; int i, error; /* * configure link-local address. */ - bzero(&ifra, sizeof(ifra)); + memset(&ifra, 0, sizeof(ifra)); /* * in6_update_ifa() does not use ifra_name, but we accurately set it @@ -345,8 +548,7 @@ in6_ifattach_linklocal(ifp, altifp) ifra.ifra_addr.sin6_family = AF_INET6; ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); - ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80); - ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); + ifra.ifra_addr.sin6_addr.s6_addr32[0] = htonl(0xfe800000); ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; if ((ifp->if_flags & IFF_LOOPBACK) != 0) { ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0; @@ -355,35 +557,27 @@ in6_ifattach_linklocal(ifp, altifp) if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) { nd6log((LOG_ERR, "%s: no ifid available\n", if_name(ifp))); - return (-1); + return -1; } } + if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL)) + return -1; ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); ifra.ifra_prefixmask.sin6_family = AF_INET6; ifra.ifra_prefixmask.sin6_addr = in6mask64; -#ifdef SCOPEDROUTING - /* take into account the sin6_scope_id field for routing */ - ifra.ifra_prefixmask.sin6_scope_id = 0xffffffff; -#endif /* link-local addresses should NEVER expire. */ ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; /* - * Do not let in6_update_ifa() do DAD, since we need a random delay - * before sending an NS at the first time the interface becomes up. - * Instead, in6_if_up() will start DAD with a proper random delay. - */ - ifra.ifra_flags |= IN6_IFF_NODAD; - - /* * Now call in6_update_ifa() to do a bunch of procedures to configure * a link-local address. We can set NULL to the 3rd argument, because * we know there's no other link-local address on the interface * and therefore we are adding one (instead of updating one). */ - if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) { + if ((error = in6_update_ifa(ifp, &ifra, NULL, + IN6_IFAUPDATE_DADDELAY)) != 0) { /* * XXX: When the interface does not support IPv6, this call * would fail in the SIOCSIFADDR ioctl. I believe the @@ -395,14 +589,9 @@ in6_ifattach_linklocal(ifp, altifp) "configure a link-local address on %s " "(errno=%d)\n", if_name(ifp), error)); - return (-1); + return -1; } - /* - * Adjust ia6_flags so that in6_if_up will perform DAD. - * XXX: Some P2P interfaces seem not to send packets just after - * becoming up, so we skip p2p interfaces for safety. - */ ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */ #ifdef DIAGNOSTIC if (!ia) { @@ -410,10 +599,6 @@ in6_ifattach_linklocal(ifp, altifp) /* NOTREACHED */ } #endif - if (in6if_do_dad(ifp) && (ifp->if_flags & IFF_POINTOPOINT) == 0) { - ia->ia6_flags &= ~IN6_IFF_NODAD; - ia->ia6_flags |= IN6_IFF_TENTATIVE; - } /* * Make the link-local prefix (fe80::/64%link) as on-link. @@ -422,11 +607,10 @@ in6_ifattach_linklocal(ifp, altifp) * and add it to the prefix list as a never-expire prefix. * XXX: this change might affect some existing code base... */ - bzero(&pr0, sizeof(pr0)); + memset(&pr0, 0, sizeof(pr0)); pr0.ndpr_ifp = ifp; /* this should be 64 at this moment. */ pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL); - pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr; pr0.ndpr_prefix = ifra.ifra_addr; /* apply the mask for safety. (nd6_prelist_add will apply it again) */ for (i = 0; i < 4; i++) { @@ -450,7 +634,7 @@ in6_ifattach_linklocal(ifp, altifp) */ if (nd6_prefix_lookup(&pr0) == NULL) { if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0) - return (error); + return error; } return 0; @@ -463,7 +647,7 @@ in6_ifattach_loopback(ifp) struct in6_aliasreq ifra; int error; - bzero(&ifra, sizeof(ifra)); + memset(&ifra, 0, sizeof(ifra)); /* * in6_update_ifa() does not use ifra_name, but we accurately set it @@ -498,11 +682,11 @@ in6_ifattach_loopback(ifp) * We are sure that this is a newly assigned address, so we can set * NULL to the 3rd arg. */ - if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) { + if ((error = in6_update_ifa(ifp, &ifra, NULL, 0)) != 0) { nd6log((LOG_ERR, "in6_ifattach_loopback: failed to configure " "the loopback address on %s (errno=%d)\n", if_name(ifp), error)); - return (-1); + return -1; } return 0; @@ -545,20 +729,21 @@ in6_nigroup(ifp, name, namelen, sa6) } /* generate 8 bytes of pseudo-random value. */ - bzero(&ctxt, sizeof(ctxt)); + memset(&ctxt, 0, sizeof(ctxt)); MD5Init(&ctxt); MD5Update(&ctxt, &l, sizeof(l)); MD5Update(&ctxt, n, l); MD5Final(digest, &ctxt); - bzero(sa6, sizeof(*sa6)); + memset(sa6, 0, sizeof(*sa6)); sa6->sin6_family = AF_INET6; sa6->sin6_len = sizeof(*sa6); sa6->sin6_addr.s6_addr16[0] = htons(0xff02); - sa6->sin6_addr.s6_addr16[1] = htons(ifp->if_index); sa6->sin6_addr.s6_addr8[11] = 2; - bcopy(digest, &sa6->sin6_addr.s6_addr32[3], + memcpy(&sa6->sin6_addr.s6_addr32[3], digest, sizeof(sa6->sin6_addr.s6_addr32[3])); + if (in6_setscope(&sa6->sin6_addr, ifp, NULL)) + return -1; /* XXX: should not fail */ return 0; } @@ -617,6 +802,8 @@ in6_ifattach(ifp, altifp) */ return; #endif + case IFT_CARP: + return; default: break; } @@ -671,7 +858,6 @@ in6_ifdetach(ifp) struct ifaddr *ifa, *next; struct rtentry *rt; short rtflags; - struct sockaddr_in6 sin6; struct in6_multi_mship *imm; /* remove ip6_mrouter stuff */ @@ -681,18 +867,16 @@ in6_ifdetach(ifp) nd6_purge(ifp); /* nuke any of IPv6 addresses we have */ - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) - { - next = ifa->ifa_list.tqe_next; + for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa; ifa = next) { + next = TAILQ_NEXT(ifa, ifa_list); if (ifa->ifa_addr->sa_family != AF_INET6) continue; in6_purgeaddr(ifa); } /* undo everything done by in6_ifattach(), just in case */ - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next) - { - next = ifa->ifa_list.tqe_next; + for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa; ifa = next) { + next = TAILQ_NEXT(ifa, ifa_list); if (ifa->ifa_addr->sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { @@ -704,7 +888,7 @@ in6_ifdetach(ifp) /* * leave from multicast groups we have joined for the interface */ - while ((imm = ia->ia6_memberships.lh_first) != NULL) { + while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) { LIST_REMOVE(imm, i6mm_chain); in6_leavegroup(imm); } @@ -721,7 +905,7 @@ in6_ifdetach(ifp) } /* remove from the linked list */ - TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); + TAILQ_REMOVE(&ifp->if_addrlist, &ia->ia_ifa, ifa_list); IFAFREE(&ia->ia_ifa); /* also remove from the IPv6 address chain(itojun&jinmei) */ @@ -755,17 +939,64 @@ in6_ifdetach(ifp) * (Or can we just delay calling nd6_purge until at this point?) */ nd6_purge(ifp); +} + +int +in6_get_tmpifid(ifp, retbuf, baseid, generate) + struct ifnet *ifp; + u_int8_t *retbuf; + const u_int8_t *baseid; + int generate; +{ + u_int8_t nullbuf[8]; + struct nd_ifinfo *ndi = ND_IFINFO(ifp); + + memset(nullbuf, 0, sizeof(nullbuf)); + if (memcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) { + /* we've never created a random ID. Create a new one. */ + generate = 1; + } + + if (generate) { + memcpy(ndi->randomseed1, baseid, sizeof(ndi->randomseed1)); - /* remove route to link-local allnodes multicast (ff02::1) */ - bzero(&sin6, sizeof(sin6)); - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = in6addr_linklocal_allnodes; - sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index); - rt = rtalloc1((struct sockaddr *)&sin6, 0); - if (rt && rt->rt_ifp == ifp) { - rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), - rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); - rtfree(rt); + /* generate_tmp_ifid will update seedn and buf */ + (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1, + ndi->randomid); + } + memcpy(retbuf, ndi->randomid, 8); + if (generate && memcmp(retbuf, nullbuf, sizeof(nullbuf)) == 0) { + /* generate_tmp_ifid could not found a good ID. */ + return -1; } + + return 0; +} + +void +in6_tmpaddrtimer(void *ignored_arg) +{ + struct nd_ifinfo *ndi; + u_int8_t nullbuf[8]; + struct ifnet *ifp; + int s = splsoftnet(); + + callout_reset(&in6_tmpaddrtimer_ch, + (ip6_temp_preferred_lifetime - ip6_desync_factor - + ip6_temp_regen_advance) * hz, in6_tmpaddrtimer, NULL); + + memset(nullbuf, 0, sizeof(nullbuf)); + TAILQ_FOREACH(ifp, &ifnet, if_list) { + ndi = ND_IFINFO(ifp); + if (memcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { + /* + * We've been generating a random ID on this interface. + * Create a new one. + */ + (void)generate_tmp_ifid(ndi->randomseed0, + ndi->randomseed1, ndi->randomid); + } + } + + splx(s); }