diff -r 80f27e12612b distrib/sets/lists/tests/mi --- a/distrib/sets/lists/tests/mi Tue Apr 21 12:23:13 2020 +0000 +++ b/distrib/sets/lists/tests/mi Wed Apr 22 00:54:02 2020 +0100 @@ -3880,7 +3880,7 @@ ./usr/tests/net/ndp/Kyuafile tests-net-tests atf,rump,kyua ./usr/tests/net/ndp/t_dad tests-net-tests atf,rump ./usr/tests/net/ndp/t_ndp tests-net-tests atf,rump -./usr/tests/net/ndp/t_ra tests-net-tests atf,rump +./usr/tests/net/ndp/t_ra tests-obsolete obsolete ./usr/tests/net/net tests-net-tests compattestfile,atf ./usr/tests/net/net/Atffile tests-net-tests compattestfile,atf ./usr/tests/net/net/Kyuafile tests-net-tests compattestfile,atf,kyua diff -r 80f27e12612b etc/rc.d/network --- a/etc/rc.d/network Tue Apr 21 12:23:13 2020 +0000 +++ b/etc/rc.d/network Wed Apr 22 00:54:02 2020 +0100 @@ -50,7 +50,6 @@ network_start_defaultroute network_start_defaultroute6 have_inet6 && - network_start_ipv6_autoconf network_wait_dad network_start_resolv network_start_local @@ -171,7 +170,6 @@ /sbin/route -q add -inet6 ::0.0.0.0 -prefixlen 96 ::1 -reject /sbin/sysctl -qw net.inet6.ip6.forwarding=0 - /sbin/sysctl -qw net.inet6.ip6.accept_rtadv=0 case $ip6mode in router) @@ -187,8 +185,10 @@ ;; autohost) - echo 'IPv6 mode: autoconfigured host' - /sbin/sysctl -qw net.inet6.ip6.accept_rtadv=1 + if ! checkyesno dhcpcd; then + warn "rtsol and kernel ra handling have been removed" + warn "please configure dhcpcd in its place." + fi ;; host) @@ -319,15 +319,14 @@ ;; dhcp) if ! checkyesno dhcpcd; then - /sbin/dhcpcd -n \ + /sbin/dhcpcd -n --dhcp \ ${dhcpcd_flags} $int fi ;; rtsol) if ! checkyesno dhcpcd; then - /sbin/sysctl -qw \ - net.inet6.ip6.accept_rtadv=1 - /sbin/dhcpcd -q6T --nodhcp6 $int + /sbin/dhcpcd -n --ipv6rs \ + ${dhcpcd_flags} $int fi ;; *) @@ -439,20 +438,6 @@ fi } -network_start_ipv6_autoconf() -{ - # IPv6 interface autoconfiguration. - - # dhcpcd will ensure DAD completes before forking - if checkyesnox rtsol && ! checkyesno dhcpcd; then - if [ "$ip6mode" = "autohost" ]; then - echo - warn "rtsol has been removed, " \ - "please configure dhcpcd in its place." - fi - fi -} - network_wait_dad() { # Wait for the DAD flags to clear from all addresses. diff -r 80f27e12612b sys/compat/common/if_43.c --- a/sys/compat/common/if_43.c Tue Apr 21 12:23:13 2020 +0000 +++ b/sys/compat/common/if_43.c Wed Apr 22 00:54:02 2020 +0100 @@ -164,7 +164,6 @@ case SIOCDIFADDR: case SIOCDIFADDR_IN6: case SIOCDIFPHYADDR: - case SIOCGDEFIFACE_IN6: case SIOCG80211NWID: case SIOCG80211STATS: case SIOCG80211ZSTATS: @@ -192,7 +191,6 @@ case SIOCIFCREATE: case SIOCIFDESTROY: case SIOCS80211NWID: - case SIOCSDEFIFACE_IN6: case SIOCSIFADDR: case SIOCSIFADDR_IN6: case SIOCSIFBRDADDR: @@ -205,9 +203,6 @@ case SIOCSIFMTU: case SIOCSIFNETMASK: case SIOCSIFNETMASK_IN6: - case SIOCSNDFLUSH_IN6: - case SIOCSPFXFLUSH_IN6: - case SIOCSRTRFLUSH_IN6: case SIOCSVH: case TAPGIFNAME: return ncmd; diff -r 80f27e12612b sys/netinet6/icmp6.c --- a/sys/netinet6/icmp6.c Tue Apr 21 12:23:13 2020 +0000 +++ b/sys/netinet6/icmp6.c Wed Apr 22 00:54:02 2020 +0100 @@ -790,33 +790,24 @@ case ND_ROUTER_SOLICIT: icmp6_ifstat_inc(rcvif, ifs6_in_routersolicit); + /* FALLTHROUGH */ + case ND_ROUTER_ADVERT: + if (icmp6->icmp6_type == ND_ROUTER_ADVERT) + icmp6_ifstat_inc(rcvif, ifs6_in_routeradvert); if (code != 0) goto badcode; - if (icmp6len < sizeof(struct nd_router_solicit)) + if ((icmp6->icmp6_type == ND_ROUTER_SOLICIT && + icmp6len < sizeof(struct nd_router_solicit)) || + (icmp6->icmp6_type == ND_ROUTER_ADVERT && + icmp6len < sizeof(struct nd_router_advert))) goto badlen; if ((n = m_copypacket(m, M_DONTWAIT)) == NULL) { /* give up local */ - nd6_rs_input(m, off, icmp6len); + nd6_rtr_cache(m, off, icmp6len, icmp6->icmp6_type); m = NULL; goto freeit; } - nd6_rs_input(n, off, icmp6len); - /* m stays. */ - break; - - case ND_ROUTER_ADVERT: - icmp6_ifstat_inc(rcvif, ifs6_in_routeradvert); - if (code != 0) - goto badcode; - if (icmp6len < sizeof(struct nd_router_advert)) - goto badlen; - if ((n = m_copypacket(m, M_DONTWAIT)) == NULL) { - /* give up local */ - nd6_ra_input(m, off, icmp6len); - m = NULL; - goto freeit; - } - nd6_ra_input(n, off, icmp6len); + nd6_rtr_cache(n, off, icmp6len, icmp6->icmp6_type); /* m stays. */ break; diff -r 80f27e12612b sys/netinet6/in6.c --- a/sys/netinet6/in6.c Tue Apr 21 12:23:13 2020 +0000 +++ b/sys/netinet6/in6.c Wed Apr 22 00:54:02 2020 +0100 @@ -407,37 +407,17 @@ return EOPNOTSUPP; switch (cmd) { - case SIOCSNDFLUSH_IN6: - case SIOCSPFXFLUSH_IN6: - case SIOCSRTRFLUSH_IN6: - case SIOCSDEFIFACE_IN6: case SIOCSIFINFO_FLAGS: case SIOCSIFINFO_IN6: /* Privileged. */ /* FALLTHROUGH */ case OSIOCGIFINFO_IN6: case SIOCGIFINFO_IN6: - case SIOCGDRLST_IN6: - case SIOCGPRLST_IN6: case SIOCGNBRINFO_IN6: - case SIOCGDEFIFACE_IN6: return nd6_ioctl(cmd, data, ifp); } switch (cmd) { - case SIOCSIFPREFIX_IN6: - case SIOCDIFPREFIX_IN6: - case SIOCAIFPREFIX_IN6: - case SIOCCIFPREFIX_IN6: - case SIOCSGIFPREFIX_IN6: - case SIOCGIFPREFIX_IN6: - log(LOG_NOTICE, - "prefix ioctls are now invalidated. " - "please use ifconfig.\n"); - return EOPNOTSUPP; - } - - switch (cmd) { case SIOCALIFADDR: case SIOCDLIFADDR: /* Privileged. */ @@ -479,9 +459,6 @@ case SIOCGIFPSRCADDR_IN6: case SIOCGIFPDSTADDR_IN6: case SIOCGIFAFLAG_IN6: - case SIOCSNDFLUSH_IN6: - case SIOCSPFXFLUSH_IN6: - case SIOCSRTRFLUSH_IN6: case SIOCGIFALIFETIME_IN6: #ifdef OSIOCGIFALIFETIME_IN6 case OSIOCGIFALIFETIME_IN6: @@ -738,10 +715,6 @@ int error, s; switch (cmd) { - case SIOCSNDFLUSH_IN6: - case SIOCSPFXFLUSH_IN6: - case SIOCSRTRFLUSH_IN6: - case SIOCSDEFIFACE_IN6: case SIOCSIFINFO_FLAGS: case SIOCSIFINFO_IN6: @@ -1461,26 +1434,6 @@ ifa_remove(ifp, &ia->ia_ifa); /* Assume ifa_remove called pserialize_perform and psref_destroy */ mutex_exit(&in6_ifaddr_lock); - - /* - * Release the reference to the ND prefix. - */ - if (ia->ia6_ndpr != NULL) { - nd6_prefix_unref(ia->ia6_ndpr); - ia->ia6_ndpr = NULL; - } - - /* - * Also, if the address being removed is autoconf'ed, call - * nd6_pfxlist_onlink_check() since the release might affect the status of - * other (detached) addresses. - */ - if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0) { - ND6_WLOCK(); - nd6_pfxlist_onlink_check(); - ND6_UNLOCK(); - } - IN6_ADDRLIST_ENTRY_DESTROY(ia); /* @@ -2239,11 +2192,6 @@ } pserialize_read_exit(s); curlwp_bindx(bound); - - /* Restore any detached prefixes */ - ND6_WLOCK(); - nd6_pfxlist_onlink_check(); - ND6_UNLOCK(); } void @@ -2270,11 +2218,6 @@ int s, bound; char ip6buf[INET6_ADDRSTRLEN]; - /* Any prefixes on this interface should be detached as well */ - ND6_WLOCK(); - nd6_pfxlist_onlink_check(); - ND6_UNLOCK(); - bound = curlwp_bind(); s = pserialize_read_enter(); IFADDR_READER_FOREACH(ifa, ifp) { @@ -2379,46 +2322,6 @@ return sizeof(*src) + sizeof(*dst); } -/* - * Provide the length of interface identifiers to be used for the link attached - * to the given interface. The length should be defined in "IPv6 over - * xxx-link" document. Note that address architecture might also define - * the length for a particular set of address prefixes, regardless of the - * link type. As clarified in rfc2462bis, those two definitions should be - * consistent, and those really are as of August 2004. - */ -int -in6_if2idlen(struct ifnet *ifp) -{ - switch (ifp->if_type) { - case IFT_ETHER: /* RFC2464 */ - case IFT_PROPVIRTUAL: /* XXX: no RFC. treat it as ether */ - case IFT_L2VLAN: /* ditto */ - case IFT_IEEE80211: /* ditto */ - case IFT_PPP: /* RFC2472 */ - case IFT_ARCNET: /* RFC2497 */ - case IFT_FRELAY: /* RFC2590 */ - case IFT_IEEE1394: /* RFC3146 */ - case IFT_GIF: /* draft-ietf-v6ops-mech-v2-07 */ - case IFT_LOOP: /* XXX: is this really correct? */ - return 64; - default: - /* - * Unknown link type: - * It might be controversial to use the today's common constant - * of 64 for these cases unconditionally. For full compliance, - * we should return an error in this case. On the other hand, - * if we simply miss the standard for the link type or a new - * standard is defined for a new link type, the IFID length - * is very likely to be the common constant. As a compromise, - * we always use the constant, but make an explicit notice - * indicating the "unknown" case. - */ - printf("in6_if2idlen: unknown link type (%d)\n", ifp->if_type); - return 64; - } -} - #define IN6_LLTBL_DEFAULT_HSIZE 32 #define IN6_LLTBL_HASH(k, h) \ (((((((k >> 8) ^ k) >> 8) ^ k) >> 8) ^ k) & ((h) - 1)) diff -r 80f27e12612b sys/netinet6/in6_ifattach.c --- a/sys/netinet6/in6_ifattach.c Tue Apr 21 12:23:13 2020 +0000 +++ b/sys/netinet6/in6_ifattach.c Wed Apr 22 00:54:02 2020 +0100 @@ -63,20 +63,13 @@ int ip6_auto_linklocal = 1; /* enable by default */ -static callout_t in6_tmpaddrtimer_ch; - - #if 0 static int get_hostid_ifid(struct ifnet *, struct in6_addr *); #endif -static int get_rand_ifid(struct in6_addr *); -static int generate_tmp_ifid(u_int8_t *, const u_int8_t *, u_int8_t *); static int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *); static int in6_ifattach_linklocal(struct ifnet *, struct ifnet *); static int in6_ifattach_loopback(struct ifnet *); -static void in6_tmpaddrtimer(void *); - #define EUI64_GBIT 0x01 #define EUI64_UBIT 0x02 #define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (/*CONSTCOND*/ 0) @@ -88,8 +81,6 @@ #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. @@ -171,146 +162,6 @@ return 0; } -static int -generate_tmp_ifid(u_int8_t *seed0, const u_int8_t *seed1, u_int8_t *ret) -{ - MD5_CTX ctxt; - u_int8_t seed[16], digest[16], nullbuf[8]; - /* - * 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) { - cprng_fast(seed, sizeof(seed)); - } 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; - int s = pserialize_read_enter(); - - IN6_ADDRLIST_READER_FOREACH(ia) { - if (!memcmp(&ia->ia_addr.sin6_addr.s6_addr[8], - ret, 8)) { - badid = 1; - break; - } - } - pserialize_read_exit(s); - } - - /* - * 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, "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. * @@ -816,87 +667,4 @@ /* remove neighbor management table */ nd6_purge(ifp, NULL); - - nd6_assert_purged(ifp); } - -int -in6_get_tmpifid(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)); - - /* 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_init(void) -{ - - /* timer for regeneration of temporary addresses randomize ID */ - callout_init(&in6_tmpaddrtimer_ch, CALLOUT_MPSAFE); - callout_setfunc(&in6_tmpaddrtimer_ch, in6_tmpaddrtimer, NULL); - in6_tmpaddrtimer_schedule(); -} - -void -in6_tmpaddrtimer_schedule(void) -{ - - callout_schedule(&in6_tmpaddrtimer_ch, - (ip6_temp_preferred_lifetime - ip6_desync_factor - - ip6_temp_regen_advance) * hz); -} - -static void -in6_tmpaddrtimer(void *ignored_arg) -{ - struct nd_ifinfo *ndi; - u_int8_t nullbuf[8]; - struct ifnet *ifp; - int s; - - /* XXX NOMPSAFE still need softnet_lock */ - mutex_enter(softnet_lock); - KERNEL_LOCK(1, NULL); - - in6_tmpaddrtimer_schedule(); - - memset(nullbuf, 0, sizeof(nullbuf)); - s = pserialize_read_enter(); - IFNET_READER_FOREACH(ifp) { - 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); - } - } - pserialize_read_exit(s); - - KERNEL_UNLOCK_ONE(NULL); - mutex_exit(softnet_lock); -} diff -r 80f27e12612b sys/netinet6/in6_proto.c --- a/sys/netinet6/in6_proto.c Tue Apr 21 12:23:13 2020 +0000 +++ b/sys/netinet6/in6_proto.c Wed Apr 22 00:54:02 2020 +0100 @@ -539,7 +539,6 @@ int ip6_sendredirects = 1; int ip6_defhlim = IPV6_DEFHLIM; int ip6_defmcasthlim = IPV6_DEFAULT_MULTICAST_HOPS; -int ip6_accept_rtadv = 0; int ip6_maxfragpackets = 200; int ip6_maxfrags = 200; int ip6_log_interval = 5; @@ -552,19 +551,10 @@ int ip6_mcast_pmtu = 0; /* enable pMTU discovery for multicast? */ int ip6_v6only = 1; int ip6_neighborgcthresh = 2048; /* Threshold # of NDP entries for GC */ -int ip6_maxifprefixes = 16; /* Max acceptable prefixes via RA per IF */ -int ip6_maxifdefrouters = 16; /* Max acceptable def routers via RA */ int ip6_maxdynroutes = 4096; /* Max # of routes created via redirect */ int ip6_keepfaith = 0; time_t ip6_log_time = 0; -int ip6_rtadv_maxroutes = 100; /* (arbitrary) initial maximum number of - * routes via rtadv expected to be - * significantly larger than common use. - * if you need to count: 3 extra initial - * routes, plus 1 per interface after the - * first one, then one per non-linklocal - * prefix */ /* icmp6 */ int pmtu_expire = 60*10; diff -r 80f27e12612b sys/netinet6/in6_var.h --- a/sys/netinet6/in6_var.h Tue Apr 21 12:23:13 2020 +0000 +++ b/sys/netinet6/in6_var.h Wed Apr 22 00:54:02 2020 +0100 @@ -310,95 +310,6 @@ struct in6_addrlifetime ifra_lifetime; }; -/* prefix type macro */ -#define IN6_PREFIX_ND 1 -#define IN6_PREFIX_RR 2 - -/* - * prefix related flags passed between kernel(NDP related part) and - * user land command(ifconfig) and daemon(rtadvd). - * Note: We originally intended to use prf_ra{} only within in6_prflags{}, but - * it was (probably unintentionally) used in nd6.h as well. Since C++ does - * not allow such a reference, prf_ra{} was then moved outside. In general, - * however, this structure should not be used directly. - */ -struct prf_ra { - u_int32_t onlink : 1; - u_int32_t autonomous : 1; - u_int32_t router : 1; - u_int32_t reserved : 5; -}; - -struct in6_prflags { - struct prf_ra prf_ra; - u_char prf_reserved1; - u_short prf_reserved2; - /* want to put this on 4byte offset */ - struct prf_rr { - u_int32_t decrvalid : 1; - u_int32_t decrprefd : 1; - u_int32_t reserved : 6; - } prf_rr; - u_char prf_reserved3; - u_short prf_reserved4; -}; - -struct in6_prefixreq { - char ipr_name[IFNAMSIZ]; - u_char ipr_origin; - u_char ipr_plen; - u_int32_t ipr_vltime; - u_int32_t ipr_pltime; - struct in6_prflags ipr_flags; - struct sockaddr_in6 ipr_prefix; -}; - -#define PR_ORIG_RA 0 -#define PR_ORIG_RR 1 -#define PR_ORIG_STATIC 2 -#define PR_ORIG_KERNEL 3 - -#define ipr_raf_onlink ipr_flags.prf_ra.onlink -#define ipr_raf_auto ipr_flags.prf_ra.autonomous - -#define ipr_statef_onlink ipr_flags.prf_state.onlink - -#define ipr_rrf_decrvalid ipr_flags.prf_rr.decrvalid -#define ipr_rrf_decrprefd ipr_flags.prf_rr.decrprefd - -struct in6_rrenumreq { - char irr_name[IFNAMSIZ]; - u_char irr_origin; - u_char irr_m_len; /* match len for matchprefix */ - u_char irr_m_minlen; /* minlen for matching prefix */ - u_char irr_m_maxlen; /* maxlen for matching prefix */ - u_char irr_u_uselen; /* uselen for adding prefix */ - u_char irr_u_keeplen; /* keeplen from matching prefix */ - struct irr_raflagmask { - u_int32_t onlink : 1; - u_int32_t autonomous : 1; - u_int32_t reserved : 6; - } irr_raflagmask; - u_int32_t irr_vltime; - u_int32_t irr_pltime; - struct in6_prflags irr_flags; - struct sockaddr_in6 irr_matchprefix; - struct sockaddr_in6 irr_useprefix; -}; - -#define irr_raf_mask_onlink irr_raflagmask.onlink -#define irr_raf_mask_auto irr_raflagmask.autonomous -#define irr_raf_mask_reserved irr_raflagmask.reserved - -#define irr_raf_onlink irr_flags.prf_ra.onlink -#define irr_raf_auto irr_flags.prf_ra.autonomous - -#define irr_statef_onlink irr_flags.prf_state.onlink - -#define irr_rrf irr_flags.prf_rr -#define irr_rrf_decrvalid irr_flags.prf_rr.decrvalid -#define irr_rrf_decrprefd irr_flags.prf_rr.decrprefd - /* * Given a pointer to an in6_ifaddr (ifaddr), * return a pointer to the addr as a sockaddr_in6 @@ -443,15 +354,15 @@ #define SIOCGIFAFLAG_IN6 _IOWR('i', 73, struct in6_ifreq) -#define SIOCGDRLST_IN6 _IOWR('i', 74, struct in6_drlist) -#define SIOCGPRLST_IN6 _IOWR('i', 75, struct in6_oprlist) +/* 74 WAS SIOCGDRLST_IN6 */ +/* 75 WAS SIOCGPRLST_IN6 */ #ifdef _KERNEL #define OSIOCGIFINFO_IN6 _IOWR('i', 76, struct in6_ondireq) #endif #define SIOCSNDFLUSH_IN6 _IOWR('i', 77, struct in6_ifreq) #define SIOCGNBRINFO_IN6 _IOWR('i', 78, struct in6_nbrinfo) -#define SIOCSPFXFLUSH_IN6 _IOWR('i', 79, struct in6_ifreq) -#define SIOCSRTRFLUSH_IN6 _IOWR('i', 80, struct in6_ifreq) +/* 79 was SIOCSPFXFLUSH_IN6 */ +/* 80 was SIOCSRTRFLUSH_IN6 */ /* 81 was old SIOCGIFALIFETIME_IN6 */ #if 0 /* withdrawn - do not reuse number 82 */ @@ -460,19 +371,19 @@ #define SIOCGIFSTAT_IN6 _IOWR('i', 83, struct in6_ifreq) #define SIOCGIFSTAT_ICMP6 _IOWR('i', 84, struct in6_ifreq) -#define SIOCSDEFIFACE_IN6 _IOWR('i', 85, struct in6_ndifreq) -#define SIOCGDEFIFACE_IN6 _IOWR('i', 86, struct in6_ndifreq) +/* 85 was SIOCSDEFIFACE_IN6 */ +/* 86 was SIOCGDEFIFACE_IN6 */ #define SIOCSIFINFO_FLAGS _IOWR('i', 87, struct in6_ndireq) /* XXX */ -#define SIOCSIFPREFIX_IN6 _IOW('i', 100, struct in6_prefixreq) /* set */ -#define SIOCGIFPREFIX_IN6 _IOWR('i', 101, struct in6_prefixreq) /* get */ -#define SIOCDIFPREFIX_IN6 _IOW('i', 102, struct in6_prefixreq) /* del */ -#define SIOCAIFPREFIX_IN6 _IOW('i', 103, struct in6_rrenumreq) /* add */ -#define SIOCCIFPREFIX_IN6 _IOW('i', 104, \ - struct in6_rrenumreq) /* change */ -#define SIOCSGIFPREFIX_IN6 _IOW('i', 105, \ - struct in6_rrenumreq) /* set global */ +/* + * 100 was SIOCSIFPREFIX_IN6 + * 101 was SIOCGIFPREFIX_IN6 + * 102 was SIOCDIFPREFIX_IN6 + * 103 was SIOCAIFPREFIX_IN6 + * 104 was SIOCCIFPREFIX_IN6 + * 105 was SIOCSGIFPREFIX_IN6 + */ #define SIOCGIFALIFETIME_IN6 _IOWR('i', 106, struct in6_ifreq) #define SIOCAIFADDR_IN6 _IOW('i', 107, struct in6_aliasreq) #define SIOCGIFINFO_IN6 _IOWR('i', 108, struct in6_ndireq) @@ -679,7 +590,6 @@ #endif void in6_init(void); -void in6_tmpaddrtimer_init(void); void in6_multi_lock(int); void in6_multi_unlock(void); @@ -703,7 +613,6 @@ void in6_purgeaddr(struct ifaddr *); void in6_purgeif(struct ifnet *); void in6_setmaxmtu (void); -int in6_if2idlen (struct ifnet *); void *in6_domifattach(struct ifnet *); void in6_domifdetach(struct ifnet *, void *); void in6_ifremlocal(struct ifaddr *); @@ -721,7 +630,6 @@ int in6_matchlen(struct in6_addr *, struct in6_addr *); int in6_are_prefix_equal(struct in6_addr *, struct in6_addr *, int); void in6_prefixlen2mask(struct in6_addr *, int); -void in6_purgeprefix(struct ifnet *); void in6_purge_mcast_references(struct in6_multi *); int ip6flow_fastforward(struct mbuf **); /* IPv6 fast forward routine */ @@ -734,8 +642,6 @@ void in6_sysctl_multicast_setup(struct sysctllog **); -void in6_tmpaddrtimer_schedule(void); - #endif /* _KERNEL */ #endif /* !_NETINET6_IN6_VAR_H_ */ diff -r 80f27e12612b sys/netinet6/ip6_input.c --- a/sys/netinet6/ip6_input.c Tue Apr 21 12:23:13 2020 +0000 +++ b/sys/netinet6/ip6_input.c Wed Apr 22 00:54:02 2020 +0100 @@ -182,9 +182,7 @@ addrsel_policy_init(); nd6_init(); frag6_init(); - ip6_desync_factor = cprng_fast32() % MAX_TEMP_DESYNC_FACTOR; - in6_tmpaddrtimer_init(); #ifdef GATEWAY ip6flow_init(ip6_hashsize); #endif @@ -1539,30 +1537,6 @@ return (NETSTAT_SYSCTL(ip6stat_percpu, IP6_NSTATS)); } -static int -sysctl_net_inet6_ip6_temppltime(SYSCTLFN_ARGS) -{ - int error; - uint32_t pltime; - struct sysctlnode node; - - node = *rnode; - node.sysctl_data = &pltime; - pltime = ip6_temp_preferred_lifetime; - error = sysctl_lookup(SYSCTLFN_CALL(&node)); - if (error || newp == NULL) - return error; - - if (pltime <= (MAX_TEMP_DESYNC_FACTOR + TEMPADDR_REGEN_ADVANCE)) - return EINVAL; - - ip6_temp_preferred_lifetime = pltime; - - in6_tmpaddrtimer_schedule(); - - return 0; -} - static void sysctl_net_inet6_ip6_setup(struct sysctllog **clog) { @@ -1611,27 +1585,6 @@ IPV6CTL_MAXFRAGPACKETS, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "accept_rtadv", - SYSCTL_DESCR("Accept router advertisements"), - NULL, 0, &ip6_accept_rtadv, 0, - CTL_NET, PF_INET6, IPPROTO_IPV6, - IPV6CTL_ACCEPT_RTADV, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "rtadv_maxroutes", - SYSCTL_DESCR("Maximum number of routes accepted via router advertisements"), - NULL, 0, &ip6_rtadv_maxroutes, 0, - CTL_NET, PF_INET6, IPPROTO_IPV6, - IPV6CTL_RTADV_MAXROUTES, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT, - CTLTYPE_INT, "rtadv_numroutes", - SYSCTL_DESCR("Current number of routes accepted via router advertisements"), - NULL, 0, &nd6_numroutes, 0, - CTL_NET, PF_INET6, IPPROTO_IPV6, - IPV6CTL_RTADV_NUMROUTES, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "keepfaith", SYSCTL_DESCR("Activate faith interface"), NULL, 0, &ip6_keepfaith, 0, @@ -1757,13 +1710,6 @@ IPV6CTL_ADDRCTLPOLICY, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "use_tempaddr", - SYSCTL_DESCR("Use temporary address"), - NULL, 0, &ip6_use_tempaddr, 0, - CTL_NET, PF_INET6, IPPROTO_IPV6, - CTL_CREATE, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "prefer_tempaddr", SYSCTL_DESCR("Prefer temporary address as source " "address"), @@ -1772,20 +1718,6 @@ CTL_CREATE, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "temppltime", - SYSCTL_DESCR("preferred lifetime of a temporary address"), - sysctl_net_inet6_ip6_temppltime, 0, NULL, 0, - CTL_NET, PF_INET6, IPPROTO_IPV6, - CTL_CREATE, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "tempvltime", - SYSCTL_DESCR("valid lifetime of a temporary address"), - NULL, 0, &ip6_temp_valid_lifetime, 0, - CTL_NET, PF_INET6, IPPROTO_IPV6, - CTL_CREATE, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "maxfrags", SYSCTL_DESCR("Maximum fragments in reassembly queue"), NULL, 0, &ip6_maxfrags, 0, @@ -1848,22 +1780,6 @@ CTL_CREATE, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "maxifprefixes", - SYSCTL_DESCR("Maximum number of prefixes created by" - " route advertisement per interface"), - NULL, 1, &ip6_maxifprefixes, 0, - CTL_NET, PF_INET6, IPPROTO_IPV6, - CTL_CREATE, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, - CTLTYPE_INT, "maxifdefrouters", - SYSCTL_DESCR("Maximum number of default routers created" - " by route advertisement per interface"), - NULL, 1, &ip6_maxifdefrouters, 0, - CTL_NET, PF_INET6, IPPROTO_IPV6, - CTL_CREATE, CTL_EOL); - sysctl_createv(clog, 0, NULL, NULL, - CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "maxdynroutes", SYSCTL_DESCR("Maximum number of routes created via" " redirect"), diff -r 80f27e12612b sys/netinet6/ip6_var.h --- a/sys/netinet6/ip6_var.h Tue Apr 21 12:23:13 2020 +0000 +++ b/sys/netinet6/ip6_var.h Wed Apr 22 00:54:02 2020 +0100 @@ -240,8 +240,6 @@ extern int ip6_mcast_pmtu; /* enable pMTU discovery for multicast? */ extern int ip6_v6only; extern int ip6_neighborgcthresh; /* Threshold # of NDP entries for GC */ -extern int ip6_maxifprefixes; /* Max acceptable prefixes via RA per IF */ -extern int ip6_maxifdefrouters; /* Max acceptable def routers via RA */ extern int ip6_maxdynroutes; /* Max # of routes created via redirect */ @@ -249,8 +247,6 @@ extern int ip6_sendredirects; /* send IP redirects when forwarding? */ extern int ip6_maxfragpackets; /* Maximum packets in reassembly queue */ extern int ip6_maxfrags; /* Maximum fragments in reassembly queue */ -extern int ip6_accept_rtadv; /* Acts as a host not a router */ -extern int ip6_rtadv_maxroutes; /* maximum number of routes via rtadv */ extern int ip6_keepfaith; /* Firewall Aided Internet Translator */ extern int ip6_log_interval; extern time_t ip6_log_time; @@ -265,7 +261,6 @@ extern int ip6_lowportmin; /* minimum reserved port */ extern int ip6_lowportmax; /* maximum reserved port */ -extern int ip6_use_tempaddr; /* whether to use temporary addresses. */ extern int ip6_prefer_tempaddr; /* whether to prefer temporary addresses in the source address selection */ extern int ip6_use_defzone; /* whether to use the default scope zone diff -r 80f27e12612b sys/netinet6/nd6.c --- a/sys/netinet6/nd6.c Tue Apr 21 12:23:13 2020 +0000 +++ b/sys/netinet6/nd6.c Wed Apr 22 00:54:02 2020 +0100 @@ -101,14 +101,10 @@ krwlock_t nd6_lock __cacheline_aligned; -struct nd_drhead nd_defrouter; -struct nd_prhead nd_prefix = { 0 }; - int nd6_recalc_reachtm_interval = ND6_RECALC_REACHTM_INTERVAL; static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *); static void nd6_slowtimo(void *); -static int regen_tmpaddr(const struct in6_ifaddr *); static void nd6_free(struct llentry *, int); static void nd6_llinfo_timer(void *); static void nd6_timer(void *); @@ -121,14 +117,6 @@ static struct workqueue *nd6_timer_wq; static struct work nd6_timer_wk; -static int fill_drlist(void *, size_t *); -static int fill_prlist(void *, size_t *); - -static struct ifnet *nd6_defifp; -static int nd6_defifindex; - -static int nd6_setdefaultiface(int); - MALLOC_DEFINE(M_IP6NDP, "NDP", "IPv6 Neighbour Discovery"); void @@ -140,9 +128,6 @@ rw_init(&nd6_lock); - /* initialization of the default router list */ - ND_DEFROUTER_LIST_INIT(); - callout_init(&nd6_slowtimo_ch, CALLOUT_MPSAFE); callout_init(&nd6_timer_ch, CALLOUT_MPSAFE); @@ -164,14 +149,12 @@ nd = kmem_zalloc(sizeof(*nd), KM_SLEEP); - nd->initialized = 1; - nd->chlim = IPV6_DEFHLIM; nd->basereachable = REACHABLE_TIME; nd->reachable = ND_COMPUTE_RTIME(nd->basereachable); nd->retrans = RETRANS_TIMER; - nd->flags = ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV; + nd->flags = ND6_IFF_PERFORMNUD; /* A loopback interface always has ND6_IFF_AUTO_LINKLOCAL. * A bridge interface should not have ND6_IFF_AUTO_LINKLOCAL @@ -180,14 +163,6 @@ (ifp->if_flags & IFF_LOOPBACK)) nd->flags |= ND6_IFF_AUTO_LINKLOCAL; - /* A loopback interface does not need to accept RTADV. - * A bridge interface should not accept RTADV - * because one of its members should. */ - if (ip6_accept_rtadv && - !(ifp->if_flags & IFF_LOOPBACK) && - !(ifp->if_type != IFT_BRIDGE)) - nd->flags |= ND6_IFF_ACCEPT_RTADV; - /* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */ nd6_setmtu0(ifp, nd); @@ -601,8 +576,6 @@ static void nd6_timer_work(struct work *wk, void *arg) { - struct nd_defrouter *next_dr, *dr; - struct nd_prefix *next_pr, *pr; struct in6_ifaddr *ia6, *nia6; int s, bound; struct psref psref; @@ -612,24 +585,8 @@ SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); - /* expire default router list */ - - ND6_WLOCK(); - ND_DEFROUTER_LIST_FOREACH_SAFE(dr, next_dr) { - if (dr->expire && dr->expire < time_uptime) { - nd6_defrtrlist_del(dr, NULL); - } - } - ND6_UNLOCK(); - - /* - * expire interface addresses. - * in the past the loop was inside prefix expiry processing. - * However, from a stricter speci-confrmance standpoint, we should - * rather separate address lifetimes and prefix lifetimes. - */ + /* expire interface addresses */ bound = curlwp_bind(); - addrloop: s = pserialize_read_enter(); for (ia6 = IN6_ADDRLIST_READER_FIRST(); ia6; ia6 = nia6) { nia6 = IN6_ADDRLIST_READER_NEXT(ia6); @@ -639,27 +596,8 @@ /* check address lifetime */ if (IFA6_IS_INVALID(ia6)) { - int regen = 0; struct ifnet *ifp; - /* - * If the expiring address is temporary, try - * regenerating a new one. This would be useful when - * we suspended a laptop PC, then turned it on after a - * period that could invalidate all temporary - * addresses. Although we may have to restart the - * loop (see below), it must be after purging the - * address. Otherwise, we'd see an infinite loop of - * regeneration. - */ - if (ip6_use_tempaddr && - (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { - IFNET_LOCK(ia6->ia_ifa.ifa_ifp); - if (regen_tmpaddr(ia6) == 0) - regen = 1; - IFNET_UNLOCK(ia6->ia_ifa.ifa_ifp); - } - ifp = ia6->ia_ifa.ifa_ifp; IFNET_LOCK(ifp); /* @@ -678,9 +616,6 @@ } ia6 = NULL; IFNET_UNLOCK(ifp); - - if (regen) - goto addrloop; /* XXX: see below */ } else if (IFA6_IS_DEPRECATED(ia6)) { int oldflags = ia6->ia6_flags; @@ -688,36 +623,6 @@ ia6->ia6_flags |= IN6_IFF_DEPRECATED; rt_addrmsg(RTM_NEWADDR, (struct ifaddr *)ia6); } - - /* - * If a temporary address has just become deprecated, - * regenerate a new one if possible. - */ - if (ip6_use_tempaddr && - (ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && - (oldflags & IN6_IFF_DEPRECATED) == 0) { - int ret; - - IFNET_LOCK(ia6->ia_ifa.ifa_ifp); - ret = regen_tmpaddr(ia6); - IFNET_UNLOCK(ia6->ia_ifa.ifa_ifp); - if (ret == 0) { - /* - * A new temporary address is - * generated. - * XXX: this means the address chain - * has changed while we are still in - * the loop. Although the change - * would not cause disaster (because - * it's not a deletion, but an - * addition,) we'd rather restart the - * loop just for safety. Or does this - * significantly reduce performance?? - */ - ia6_release(ia6, &psref); - goto addrloop; - } - } } else { /* * A new RA might have made a deprecated address @@ -734,27 +639,6 @@ pserialize_read_exit(s); curlwp_bindx(bound); - /* expire prefix list */ - ND6_WLOCK(); - ND_PREFIX_LIST_FOREACH_SAFE(pr, next_pr) { - /* - * check prefix lifetime. - * since pltime is just for autoconf, pltime processing for - * prefix is not necessary. - */ - if (pr->ndpr_vltime != ND6_INFINITE_LIFETIME && - time_uptime - pr->ndpr_lastupdate > pr->ndpr_vltime) { - /* - * Just invalidate the prefix here. Removing it - * will be done when purging an associated address. - */ - KASSERTMSG(pr->ndpr_refcnt > 0, "ndpr_refcnt=%d", - pr->ndpr_refcnt); - nd6_invalidate_prefix(pr); - } - } - ND6_UNLOCK(); - SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); } @@ -765,98 +649,6 @@ workqueue_enqueue(nd6_timer_wq, &nd6_timer_wk, NULL); } -/* ia6: deprecated/invalidated temporary address */ -static int -regen_tmpaddr(const struct in6_ifaddr *ia6) -{ - struct ifaddr *ifa; - struct ifnet *ifp; - struct in6_ifaddr *public_ifa6 = NULL; - int s; - - ifp = ia6->ia_ifa.ifa_ifp; - s = pserialize_read_enter(); - IFADDR_READER_FOREACH(ifa, ifp) { - struct in6_ifaddr *it6; - - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - - it6 = (struct in6_ifaddr *)ifa; - - /* ignore no autoconf addresses. */ - if ((it6->ia6_flags & IN6_IFF_AUTOCONF) == 0) - continue; - - /* ignore autoconf addresses with different prefixes. */ - if (it6->ia6_ndpr == NULL || it6->ia6_ndpr != ia6->ia6_ndpr) - continue; - - /* - * Now we are looking at an autoconf address with the same - * prefix as ours. If the address is temporary and is still - * preferred, do not create another one. It would be rare, but - * could happen, for example, when we resume a laptop PC after - * a long period. - */ - if ((it6->ia6_flags & IN6_IFF_TEMPORARY) != 0 && - !IFA6_IS_DEPRECATED(it6)) { - public_ifa6 = NULL; - break; - } - - /* - * This is a public autoconf address that has the same prefix - * as ours. If it is preferred, keep it. We can't break the - * loop here, because there may be a still-preferred temporary - * address with the prefix. - */ - if (!IFA6_IS_DEPRECATED(it6)) - public_ifa6 = it6; - } - - if (public_ifa6 != NULL) { - int e; - struct psref psref; - - ia6_acquire(public_ifa6, &psref); - pserialize_read_exit(s); - /* - * Random factor is introduced in the preferred lifetime, so - * we do not need additional delay (3rd arg to in6_tmpifadd). - */ - ND6_WLOCK(); - e = in6_tmpifadd(public_ifa6, 0, 0); - ND6_UNLOCK(); - if (e != 0) { - ia6_release(public_ifa6, &psref); - log(LOG_NOTICE, "regen_tmpaddr: failed to create a new" - " tmp addr, errno=%d\n", e); - return -1; - } - ia6_release(public_ifa6, &psref); - return 0; - } - pserialize_read_exit(s); - - return -1; -} - -bool -nd6_accepts_rtadv(const struct nd_ifinfo *ndi) -{ - switch (ndi->flags & (ND6_IFF_ACCEPT_RTADV|ND6_IFF_OVERRIDE_RTADV)) { - case ND6_IFF_OVERRIDE_RTADV|ND6_IFF_ACCEPT_RTADV: - return true; - case ND6_IFF_ACCEPT_RTADV: - return ip6_accept_rtadv != 0; - case ND6_IFF_OVERRIDE_RTADV: - case 0: - default: - return false; - } -} - /* * Nuke neighbor cache/prefix/default router management table, right before * ifp goes away. @@ -864,8 +656,6 @@ void nd6_purge(struct ifnet *ifp, struct in6_ifextra *ext) { - struct nd_defrouter *dr, *ndr; - struct nd_prefix *pr, *npr; /* * During detach, the ND info might be already removed, but @@ -877,59 +667,6 @@ if (ext == NULL) return; - ND6_WLOCK(); - /* - * Nuke default router list entries toward ifp. - * We defer removal of default router list entries that is installed - * in the routing table, in order to keep additional side effects as - * small as possible. - */ - ND_DEFROUTER_LIST_FOREACH_SAFE(dr, ndr) { - if (dr->installed) - continue; - - if (dr->ifp == ifp) { - KASSERT(ext != NULL); - nd6_defrtrlist_del(dr, ext); - } - } - - ND_DEFROUTER_LIST_FOREACH_SAFE(dr, ndr) { - if (!dr->installed) - continue; - - if (dr->ifp == ifp) { - KASSERT(ext != NULL); - nd6_defrtrlist_del(dr, ext); - } - } - - /* Nuke prefix list entries toward ifp */ - ND_PREFIX_LIST_FOREACH_SAFE(pr, npr) { - if (pr->ndpr_ifp == ifp) { - /* - * All addresses referencing pr should be already freed. - */ - KASSERTMSG(pr->ndpr_refcnt == 0, "ndpr_refcnt=%d", - pr->ndpr_refcnt); - nd6_prelist_remove(pr); - } - } - - /* cancel default outgoing interface setting */ - if (nd6_defifindex == ifp->if_index) - nd6_setdefaultiface(0); - - /* XXX: too restrictive? */ - if (!ip6_forwarding && ifp->if_afdata[AF_INET6]) { - struct nd_ifinfo *ndi = ND_IFINFO(ifp); - if (ndi && nd6_accepts_rtadv(ndi)) { - /* refresh default router list */ - nd6_defrouter_select(); - } - } - ND6_UNLOCK(); - /* * We may not need to nuke the neighbor cache entries here * because the neighbor cache is kept in if_afdata[AF_INET6]. @@ -942,29 +679,6 @@ lltable_purge_entries(ext->lltable); } -void -nd6_assert_purged(struct ifnet *ifp) -{ - struct nd_defrouter *dr; - struct nd_prefix *pr; - char ip6buf[INET6_ADDRSTRLEN] __diagused; - - ND6_RLOCK(); - ND_DEFROUTER_LIST_FOREACH(dr) { - KASSERTMSG(dr->ifp != ifp, - "defrouter %s remains on %s", - IN6_PRINT(ip6buf, &dr->rtaddr), ifp->if_xname); - } - - ND_PREFIX_LIST_FOREACH(pr) { - KASSERTMSG(pr->ndpr_ifp != ifp, - "prefix %s/%d remains on %s", - IN6_PRINT(ip6buf, &pr->ndpr_prefix.sin6_addr), - pr->ndpr_plen, ifp->if_xname); - } - ND6_UNLOCK(); -} - struct llentry * nd6_lookup(const struct in6_addr *addr6, const struct ifnet *ifp, bool wlock) { @@ -1011,7 +725,6 @@ static int nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) { - struct nd_prefix *pr; struct ifaddr *dstaddr; int s; @@ -1039,49 +752,6 @@ } /* - * If the address matches one of our addresses, - * it should be a neighbor. - * If the address matches one of our on-link prefixes, it should be a - * neighbor. - */ - ND6_RLOCK(); - ND_PREFIX_LIST_FOREACH(pr) { - if (pr->ndpr_ifp != ifp) - continue; - - if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) { - struct rtentry *rt; - - rt = rtalloc1(sin6tosa(&pr->ndpr_prefix), 0); - if (rt == NULL) - continue; - /* - * This is the case where multiple interfaces - * have the same prefix, but only one is installed - * into the routing table and that prefix entry - * is not the one being examined here. In the case - * where RADIX_MPATH is enabled, multiple route - * entries (of the same rt_key value) will be - * installed because the interface addresses all - * differ. - */ - if (!IN6_ARE_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, - &satocsin6(rt_getkey(rt))->sin6_addr)) { - rt_unref(rt); - continue; - } - rt_unref(rt); - } - - if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, - &addr->sin6_addr, &pr->ndpr_mask)) { - ND6_UNLOCK(); - return 1; - } - } - ND6_UNLOCK(); - - /* * If the address is assigned on the node of the other side of * a p2p interface, the address should be a neighbor. */ @@ -1095,18 +765,6 @@ } pserialize_read_exit(s); - /* - * If the default router list is empty, all addresses are regarded - * as on-link, and thus, as a neighbor. - */ - ND6_RLOCK(); - if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && - ND_DEFROUTER_LIST_EMPTY() && nd6_defifindex == ifp->if_index) { - ND6_UNLOCK(); - return 1; - } - ND6_UNLOCK(); - return 0; } @@ -1117,7 +775,6 @@ int nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) { - struct nd_prefix *pr; struct llentry *ln; struct rtentry *rt; @@ -1144,38 +801,6 @@ return 0; } - /* - * If the address matches one of our on-link prefixes, it should be a - * neighbor. - */ - ND6_RLOCK(); - ND_PREFIX_LIST_FOREACH(pr) { - if (pr->ndpr_ifp != ifp) - continue; - - if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) - continue; - - if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, - &addr->sin6_addr, &pr->ndpr_mask)) { - ND6_UNLOCK(); - return 1; - } - } - - /* - * If the default router list is empty, all addresses are regarded - * as on-link, and thus, as a neighbor. - * XXX: we restrict the condition to hosts, because routers usually do - * not have the "default router list". - */ - if (!ip6_forwarding && ND_DEFROUTER_LIST_EMPTY() && - nd6_defifindex == ifp->if_index) { - ND6_UNLOCK(); - return 1; - } - ND6_UNLOCK(); - if (nd6_is_new_addr_neighbor(addr, ifp)) return 1; @@ -1222,101 +847,36 @@ nd6_free(struct llentry *ln, int gc) { struct ifnet *ifp; - struct in6_addr *in6; KASSERT(ln != NULL); LLE_WLOCK_ASSERT(ln); - ifp = ln->lle_tbl->llt_ifp; - in6 = &ln->r_l3addr.addr6; /* - * we used to have pfctlinput(PRC_HOSTDEAD) here. - * even though it is not harmful, it was not really necessary. + * If the reason for the deletion is just garbage collection, + * and the neighbor is an active router, do not delete it. + * Instead, reset the GC timer using the router's lifetime. + * XXX: the check for ln_state should be redundant, + * but we intentionally keep it just in case. */ - - if (!ip6_forwarding && ln->ln_router) { - if (ln->ln_state == ND6_LLINFO_STALE && gc) { - /* - * If the reason for the deletion is just garbage - * collection, and the neighbor is an active - * router, do not delete it. Instead, reset the GC - * timer using the router's lifetime. - * Simply deleting the entry may affect default - * router selection, which is not necessarily a good - * thing, especially when we're using router preference - * values. - * XXX: the check for ln_state would be redundant, - * but we intentionally keep it just in case. - */ - if (ln->ln_expire > time_uptime) - nd6_llinfo_settimer(ln, - (ln->ln_expire - time_uptime) * hz); - else - nd6_llinfo_settimer(ln, nd6_gctimer * hz); - LLE_WUNLOCK(ln); - return; - } - - ND6_WLOCK(); + if (!ip6_forwarding && ln->ln_router && + ln->ln_state == ND6_LLINFO_STALE && gc) + { + if (ln->ln_expire > time_uptime) + nd6_llinfo_settimer(ln, + (ln->ln_expire - time_uptime) * hz); + else + nd6_llinfo_settimer(ln, nd6_gctimer * hz); + LLE_WUNLOCK(ln); + return; + } - /* - * We need to unlock to avoid a LOR with nd6_rt_flush() - * with the rnh and for the calls to - * nd6_pfxlist_onlink_check() and nd6_defrouter_select() in the - * block further down for calls into nd6_lookup(). - * We still hold a ref. - * - * Temporarily fake the state to choose a new default - * router and to perform on-link determination of - * prefixes correctly. - * Below the state will be set correctly, - * or the entry itself will be deleted. - */ - ln->ln_state = ND6_LLINFO_INCOMPLETE; - LLE_WUNLOCK(ln); - - /* - * nd6_rt_flush must be called whether or not the neighbor - * is in the Default Router List. - * See a corresponding comment in nd6_na_input(). - */ - nd6_rt_flush(in6, ifp); - - /* - * Unreachablity of a router might affect the default - * router selection and on-link detection of advertised - * prefixes. - * - * Since nd6_defrouter_select() does not affect the - * on-link determination and MIP6 needs the check - * before the default router selection, we perform - * the check now. - */ - nd6_pfxlist_onlink_check(); - - /* - * refresh default router list - */ - nd6_defrouter_select(); - -#ifdef __FreeBSD__ - /* - * If this entry was added by an on-link redirect, remove the - * corresponding host route. - */ - if (ln->la_flags & LLE_REDIRECT) - nd6_free_redirect(ln); -#endif - - ND6_UNLOCK(); - LLE_WLOCK(ln); - } + ifp = ln->lle_tbl->llt_ifp; if (ln->la_flags & LLE_VALID || gc) { struct sockaddr_in6 sin6; const char *lladdr; - sockaddr_in6_init(&sin6, in6, 0, 0, 0); + sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); lladdr = ln->la_flags & LLE_VALID ? (const char *)&ln->ll_addr : NULL; rt_clonedmsg(RTM_DELETE, NULL, sin6tosa(&sin6), lladdr, ifp); @@ -1657,102 +1217,11 @@ int nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) { - struct in6_drlist *drl = (struct in6_drlist *)data; - struct in6_oprlist *oprl = (struct in6_oprlist *)data; struct in6_ndireq *ndi = (struct in6_ndireq *)data; struct in6_nbrinfo *nbi = (struct in6_nbrinfo *)data; - struct in6_ndifreq *ndif = (struct in6_ndifreq *)data; - struct nd_defrouter *dr; - struct nd_prefix *pr; - int i = 0, error = 0; + int error = 0; switch (cmd) { - case SIOCGDRLST_IN6: - /* - * obsolete API, use sysctl under net.inet6.icmp6 - */ - memset(drl, 0, sizeof(*drl)); - ND6_RLOCK(); - ND_DEFROUTER_LIST_FOREACH(dr) { - if (i >= DRLSTSIZ) - break; - drl->defrouter[i].rtaddr = dr->rtaddr; - in6_clearscope(&drl->defrouter[i].rtaddr); - - drl->defrouter[i].flags = dr->flags; - drl->defrouter[i].rtlifetime = dr->rtlifetime; - drl->defrouter[i].expire = dr->expire ? - time_mono_to_wall(dr->expire) : 0; - drl->defrouter[i].if_index = dr->ifp->if_index; - i++; - } - ND6_UNLOCK(); - break; - case SIOCGPRLST_IN6: - /* - * obsolete API, use sysctl under net.inet6.icmp6 - * - * XXX the structure in6_prlist was changed in backward- - * incompatible manner. in6_oprlist is used for SIOCGPRLST_IN6, - * in6_prlist is used for nd6_sysctl() - fill_prlist(). - */ - /* - * XXX meaning of fields, especialy "raflags", is very - * differnet between RA prefix list and RR/static prefix list. - * how about separating ioctls into two? - */ - memset(oprl, 0, sizeof(*oprl)); - ND6_RLOCK(); - ND_PREFIX_LIST_FOREACH(pr) { - struct nd_pfxrouter *pfr; - int j; - - if (i >= PRLSTSIZ) - break; - oprl->prefix[i].prefix = pr->ndpr_prefix.sin6_addr; - oprl->prefix[i].raflags = pr->ndpr_raf; - oprl->prefix[i].prefixlen = pr->ndpr_plen; - oprl->prefix[i].vltime = pr->ndpr_vltime; - oprl->prefix[i].pltime = pr->ndpr_pltime; - oprl->prefix[i].if_index = pr->ndpr_ifp->if_index; - if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) - oprl->prefix[i].expire = 0; - else { - time_t maxexpire; - - /* XXX: we assume time_t is signed. */ - maxexpire = (-1) & - ~((time_t)1 << - ((sizeof(maxexpire) * 8) - 1)); - if (pr->ndpr_vltime < - maxexpire - pr->ndpr_lastupdate) { - time_t expire; - expire = pr->ndpr_lastupdate + - pr->ndpr_vltime; - oprl->prefix[i].expire = expire ? - time_mono_to_wall(expire) : 0; - } else - oprl->prefix[i].expire = maxexpire; - } - - j = 0; - LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { - if (j < DRLSTSIZ) { -#define RTRADDR oprl->prefix[i].advrtr[j] - RTRADDR = pfr->router->rtaddr; - in6_clearscope(&RTRADDR); -#undef RTRADDR - } - j++; - } - oprl->prefix[i].advrtrs = j; - oprl->prefix[i].origin = PR_ORIG_RA; - - i++; - } - ND6_UNLOCK(); - - break; case OSIOCGIFINFO_IN6: #define ND ndi->ndi /* XXX: old ndp(8) assumes a positive value for linkmtu. */ @@ -1900,113 +1369,6 @@ ND_IFINFO(ifp)->flags = ND.flags; break; #undef ND - case SIOCSNDFLUSH_IN6: /* XXX: the ioctl name is confusing... */ - /* sync kernel routing table with the default router list */ - ND6_WLOCK(); - nd6_defrouter_reset(); - nd6_defrouter_select(); - ND6_UNLOCK(); - break; - case SIOCSPFXFLUSH_IN6: - { - /* flush all the prefix advertised by routers */ - struct nd_prefix *pfx, *next; - - restart: - ND6_WLOCK(); - ND_PREFIX_LIST_FOREACH_SAFE(pfx, next) { - struct in6_ifaddr *ia, *ia_next; - int _s; - - /* Only flush prefixes for the given interface. */ - if (ifp != lo0ifp && ifp != pfx->ndpr_ifp) - continue; - - if (IN6_IS_ADDR_LINKLOCAL(&pfx->ndpr_prefix.sin6_addr)) - continue; /* XXX */ - - /* do we really have to remove addresses as well? */ - _s = pserialize_read_enter(); - for (ia = IN6_ADDRLIST_READER_FIRST(); ia; - ia = ia_next) { - struct ifnet *ifa_ifp; - int bound; - struct psref psref; - - /* ia might be removed. keep the next ptr. */ - ia_next = IN6_ADDRLIST_READER_NEXT(ia); - - if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) - continue; - - if (ia->ia6_ndpr != pfx) - continue; - - bound = curlwp_bind(); - ia6_acquire(ia, &psref); - pserialize_read_exit(_s); - ND6_UNLOCK(); - - ifa_ifp = ia->ia_ifa.ifa_ifp; - if (ifa_ifp == ifp) { - /* Already have IFNET_LOCK(ifp) */ - KASSERT(!if_is_deactivated(ifp)); - ia6_release(ia, &psref); - in6_purgeaddr(&ia->ia_ifa); - curlwp_bindx(bound); - goto restart; - } - IFNET_LOCK(ifa_ifp); - /* - * Need to take the lock first to prevent - * if_detach from running in6_purgeaddr - * concurrently. - */ - if (!if_is_deactivated(ifa_ifp)) { - ia6_release(ia, &psref); - in6_purgeaddr(&ia->ia_ifa); - } else { - /* - * ifp is being destroyed, ia will be - * destroyed by if_detach. - */ - ia6_release(ia, &psref); - /* XXX may cause busy loop */ - } - IFNET_UNLOCK(ifa_ifp); - curlwp_bindx(bound); - goto restart; - } - pserialize_read_exit(_s); - - KASSERTMSG(pfx->ndpr_refcnt == 0, "ndpr_refcnt=%d", - pfx->ndpr_refcnt); - nd6_prelist_remove(pfx); - } - ND6_UNLOCK(); - break; - } - case SIOCSRTRFLUSH_IN6: - { - /* flush all the default routers */ - struct nd_defrouter *drtr, *next; - - ND6_WLOCK(); -#if 0 - /* XXX Is this really needed? */ - nd6_defrouter_reset(); -#endif - ND_DEFROUTER_LIST_FOREACH_SAFE(drtr, next) { - /* Only flush routers for the given interface. */ - if (ifp != lo0ifp && ifp != drtr->ifp) - continue; - - nd6_defrtrlist_del(drtr, NULL); - } - nd6_defrouter_select(); - ND6_UNLOCK(); - break; - } case SIOCGNBRINFO_IN6: { struct llentry *ln; @@ -2029,11 +1391,6 @@ break; } - case SIOCGDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ - ndif->ifindex = nd6_defifindex; - break; - case SIOCSDEFIFACE_IN6: /* XXX: should be implemented as a sysctl? */ - return nd6_setdefaultiface(ndif->ifindex); } return error; } @@ -2079,14 +1436,12 @@ int code /* type dependent information */ ) { - struct nd_ifinfo *ndi = ND_IFINFO(ifp); struct llentry *ln = NULL; int is_newentry; int do_update; int olladdr; int llchange; int newstate = 0; - uint16_t router = 0; KASSERT(ifp != NULL); KASSERT(from != NULL); @@ -2263,10 +1618,8 @@ NULL, sin6tosa(&sin6), lladdr, ifp); } - if (ln != NULL) { - router = ln->ln_router; + if (ln != NULL) LLE_WUNLOCK(ln); - } /* * If we have too many cache entries, initiate immediate @@ -2274,28 +1627,6 @@ */ if (is_newentry) nd6_gc_neighbors(LLTABLE6(ifp), &ln->r_l3addr.addr6); - - /* - * When the link-layer address of a router changes, select the - * best router again. In particular, when the neighbor entry is newly - * created, it might affect the selection policy. - * Question: can we restrict the first condition to the "is_newentry" - * case? - * XXX: when we hear an RA from a new router with the link-layer - * address option, nd6_defrouter_select() is called twice, since - * defrtrlist_update called the function as well. However, I believe - * we can compromise the overhead, since it only happens the first - * time. - * XXX: although nd6_defrouter_select() should not have a bad effect - * for those are not autoconfigured hosts, we explicitly avoid such - * cases for safety. - */ - if (do_update && router && !ip6_forwarding && - nd6_accepts_rtadv(ndi)) { - ND6_WLOCK(); - nd6_defrouter_select(); - ND6_UNLOCK(); - } } static void @@ -2536,225 +1867,17 @@ size_t newlen ) { - int (*fill_func)(void *, size_t *); if (newp) return EPERM; switch (name) { - case ICMPV6CTL_ND6_DRLIST: - fill_func = fill_drlist; - break; - + case ICMPV6CTL_ND6_DRLIST: /* FALLTHROUGH */ case ICMPV6CTL_ND6_PRLIST: - fill_func = fill_prlist; - break; - + return ENOTSUP; case ICMPV6CTL_ND6_MAXQLEN: return 0; - default: return ENOPROTOOPT; } - - if (oldlenp == NULL) - return EINVAL; - - size_t ol; - int error = (*fill_func)(NULL, &ol); /* calc len needed */ - if (error) - return error; - - if (oldp == NULL) { - *oldlenp = ol; - return 0; - } - - ol = *oldlenp = uimin(ol, *oldlenp); - if (ol == 0) - return 0; - - void *p = kmem_alloc(ol, KM_SLEEP); - error = (*fill_func)(p, oldlenp); - if (!error) - error = copyout(p, oldp, *oldlenp); - kmem_free(p, ol); - - return error; } - -static int -fill_drlist(void *oldp, size_t *oldlenp) -{ - int error = 0; - struct in6_defrouter *d = NULL, *de = NULL; - struct nd_defrouter *dr; - size_t l; - - if (oldp) { - d = (struct in6_defrouter *)oldp; - de = (struct in6_defrouter *)((char *)oldp + *oldlenp); - } - l = 0; - - ND6_RLOCK(); - ND_DEFROUTER_LIST_FOREACH(dr) { - - if (oldp && d + 1 <= de) { - memset(d, 0, sizeof(*d)); - sockaddr_in6_init(&d->rtaddr, &dr->rtaddr, 0, 0, 0); - if (sa6_recoverscope(&d->rtaddr)) { - char ip6buf[INET6_ADDRSTRLEN]; - log(LOG_ERR, - "scope error in router list (%s)\n", - IN6_PRINT(ip6buf, &d->rtaddr.sin6_addr)); - /* XXX: press on... */ - } - d->flags = dr->flags; - d->rtlifetime = dr->rtlifetime; - d->expire = dr->expire ? - time_mono_to_wall(dr->expire) : 0; - d->if_index = dr->ifp->if_index; - } - - l += sizeof(*d); - if (d) - d++; - } - ND6_UNLOCK(); - - *oldlenp = l; /* (void *)d - (void *)oldp */ - - return error; -} - -static int -fill_prlist(void *oldp, size_t *oldlenp) -{ - int error = 0; - struct nd_prefix *pr; - uint8_t *p = NULL, *ps = NULL; - uint8_t *pe = NULL; - size_t l; - char ip6buf[INET6_ADDRSTRLEN]; - - if (oldp) { - ps = p = (uint8_t*)oldp; - pe = (uint8_t*)oldp + *oldlenp; - } - l = 0; - - ND6_RLOCK(); - ND_PREFIX_LIST_FOREACH(pr) { - u_short advrtrs; - struct sockaddr_in6 sin6; - struct nd_pfxrouter *pfr; - struct in6_prefix pfx; - - if (oldp && p + sizeof(struct in6_prefix) <= pe) - { - memset(&pfx, 0, sizeof(pfx)); - ps = p; - pfx.prefix = pr->ndpr_prefix; - - if (sa6_recoverscope(&pfx.prefix)) { - log(LOG_ERR, - "scope error in prefix list (%s)\n", - IN6_PRINT(ip6buf, &pfx.prefix.sin6_addr)); - /* XXX: press on... */ - } - pfx.raflags = pr->ndpr_raf; - pfx.prefixlen = pr->ndpr_plen; - pfx.vltime = pr->ndpr_vltime; - pfx.pltime = pr->ndpr_pltime; - pfx.if_index = pr->ndpr_ifp->if_index; - if (pr->ndpr_vltime == ND6_INFINITE_LIFETIME) - pfx.expire = 0; - else { - time_t maxexpire; - - /* XXX: we assume time_t is signed. */ - maxexpire = (-1) & - ~((time_t)1 << - ((sizeof(maxexpire) * 8) - 1)); - if (pr->ndpr_vltime < - maxexpire - pr->ndpr_lastupdate) { - pfx.expire = pr->ndpr_lastupdate + - pr->ndpr_vltime; - } else - pfx.expire = maxexpire; - } - pfx.refcnt = pr->ndpr_refcnt; - pfx.flags = pr->ndpr_stateflags; - pfx.origin = PR_ORIG_RA; - - p += sizeof(pfx); l += sizeof(pfx); - - advrtrs = 0; - LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { - if (p + sizeof(sin6) > pe) { - advrtrs++; - continue; - } - - sockaddr_in6_init(&sin6, &pfr->router->rtaddr, - 0, 0, 0); - if (sa6_recoverscope(&sin6)) { - log(LOG_ERR, - "scope error in " - "prefix list (%s)\n", - IN6_PRINT(ip6buf, - &pfr->router->rtaddr)); - } - advrtrs++; - memcpy(p, &sin6, sizeof(sin6)); - p += sizeof(sin6); - l += sizeof(sin6); - } - pfx.advrtrs = advrtrs; - memcpy(ps, &pfx, sizeof(pfx)); - } - else { - l += sizeof(pfx); - advrtrs = 0; - LIST_FOREACH(pfr, &pr->ndpr_advrtrs, pfr_entry) { - advrtrs++; - l += sizeof(sin6); - } - } - } - ND6_UNLOCK(); - - *oldlenp = l; - - return error; -} - -static int -nd6_setdefaultiface(int ifindex) -{ - ifnet_t *ifp; - int error = 0; - int s; - - s = pserialize_read_enter(); - ifp = if_byindex(ifindex); - if (ifp == NULL) { - pserialize_read_exit(s); - return EINVAL; - } - if (nd6_defifindex != ifindex) { - nd6_defifindex = ifindex; - nd6_defifp = nd6_defifindex > 0 ? ifp : NULL; - - /* - * Our current implementation assumes one-to-one maping between - * interfaces and links, so it would be natural to use the - * default interface as the default link. - */ - scope6_setdefault(nd6_defifp); - } - pserialize_read_exit(s); - - return (error); -} diff -r 80f27e12612b sys/netinet6/nd6.h --- a/sys/netinet6/nd6.h Tue Apr 21 12:23:13 2020 +0000 +++ b/sys/netinet6/nd6.h Wed Apr 22 00:54:02 2020 +0100 @@ -57,44 +57,17 @@ u_int32_t flags; /* Flags */ int recalctm; /* BaseReacable re-calculation timer */ u_int8_t chlim; /* CurHopLimit */ - u_int8_t initialized; /* Flag to see the entry is initialized */ - /* the following 3 members are for privacy extension for addrconf */ - u_int8_t randomseed0[8]; /* upper 64 bits of MD5 digest */ - u_int8_t randomseed1[8]; /* lower 64 bits (usually the EUI64 IFID) */ - u_int8_t randomid[8]; /* current random ID */ }; #define ND6_IFF_PERFORMNUD 0x01 -#define ND6_IFF_ACCEPT_RTADV 0x02 /* See "RTADV Key", below. */ +/* 0x02 was ND6_IFF_ACCEPT_RTADV */ #define ND6_IFF_PREFER_SOURCE 0x04 /* XXX: not related to ND. */ #define ND6_IFF_IFDISABLED 0x08 /* IPv6 operation is disabled due to * DAD failure. (XXX: not ND-specific) */ -#define ND6_IFF_OVERRIDE_RTADV 0x10 /* See "RTADV Key", below. */ +/* 0x10 was ND6_IFF_OVERRIDE_RTADV */ #define ND6_IFF_AUTO_LINKLOCAL 0x20 -/* - * RTADV Key - * - * The flags ND6_IFF_ACCEPT_RTADV and ND6_IFF_OVERRIDE_RTADV form a - * tri-state variable. (There are actually four different states, but - * two of the states are functionally identical.) - * - * ND6_IFF_OVERRIDE_RTADV or 0: This interface does not accept - * Router Advertisements. - * - * ND6_IFF_OVERRIDE_RTADV| - * ND6_IFF_ACCEPT_RTADV: This interface accepts Router - * Advertisements regardless of the - * global setting, ip6_accept_rtadv. - * - * ND6_IFF_ACCEPT_RTADV: This interface follows the global setting, - * ip6_accept_rtadv. If ip6_accept_rtadv == 0, - * this interface does not accept Router - * Advertisements. If ip6_accept_rtadv != 0, - * this interface does accept them. - */ - #ifdef _KERNEL #define ND_IFINFO(ifp) \ (((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->nd_ifinfo) @@ -114,76 +87,6 @@ int expire; /* lifetime for NDP state transition */ }; -#define DRLSTSIZ 10 -#define PRLSTSIZ 10 -struct in6_drlist { - char ifname[IFNAMSIZ]; - struct { - struct in6_addr rtaddr; - u_char flags; - u_short rtlifetime; - u_long expire; - u_short if_index; - } defrouter[DRLSTSIZ]; -}; - -struct in6_defrouter { - struct sockaddr_in6 rtaddr; - u_char flags; - u_short rtlifetime; - u_long expire; - u_short if_index; -}; - -#ifdef _KERNEL -struct in6_oprlist { - char ifname[IFNAMSIZ]; - struct { - struct in6_addr prefix; - struct prf_ra raflags; - u_char prefixlen; - u_char origin; - u_long vltime; - u_long pltime; - u_long expire; - u_short if_index; - u_short advrtrs; /* number of advertisement routers */ - struct in6_addr advrtr[DRLSTSIZ]; /* XXX: explicit limit */ - } prefix[PRLSTSIZ]; -}; -#endif - -struct in6_prlist { - char ifname[IFNAMSIZ]; - struct { - struct in6_addr prefix; - struct prf_ra raflags; - u_char prefixlen; - u_char origin; - u_int32_t vltime; - u_int32_t pltime; - time_t expire; - u_short if_index; - u_short advrtrs; /* number of advertisement routers */ - struct in6_addr advrtr[DRLSTSIZ]; /* XXX: explicit limit */ - } prefix[PRLSTSIZ]; -}; - -struct in6_prefix { - struct sockaddr_in6 prefix; - struct prf_ra raflags; - u_char prefixlen; - u_char origin; - u_int32_t vltime; - u_int32_t pltime; - time_t expire; - u_int32_t flags; - int refcnt; - u_short if_index; - u_short advrtrs; /* number of advertisement routers */ - /* struct sockaddr_in6 advrtr[] */ -}; - #ifdef _KERNEL struct in6_ondireq { char ifname[IFNAMSIZ]; @@ -206,21 +109,8 @@ struct nd_ifinfo ndi; }; -struct in6_ndifreq { - char ifname[IFNAMSIZ]; - u_long ifindex; -}; - -/* Prefix status */ -#define NDPRF_ONLINK 0x1 -#define NDPRF_DETACHED 0x2 -#define NDPRF_HOME 0x4 - /* protocol constants */ #define MAX_RTR_SOLICITATION_DELAY 1 /* 1sec */ -#define RTR_SOLICITATION_INTERVAL 4 /* 4sec */ -#define MAX_RTR_SOLICITATIONS 3 - #define ND6_INFINITE_LIFETIME ((u_int32_t)~0) #ifdef _KERNEL @@ -230,132 +120,10 @@ #define RETRANS_TIMER 1000 /* msec */ #define MIN_RANDOM_FACTOR 512 /* 1024 * 0.5 */ #define MAX_RANDOM_FACTOR 1536 /* 1024 * 1.5 */ -#define DEF_TEMP_VALID_LIFETIME 604800 /* 1 week */ -#define DEF_TEMP_PREFERRED_LIFETIME 86400 /* 1 day */ -#define TEMPADDR_REGEN_ADVANCE 5 /* sec */ -#define MAX_TEMP_DESYNC_FACTOR 600 /* 10 min */ #define ND_COMPUTE_RTIME(x) \ (((MIN_RANDOM_FACTOR * (x >> 10)) + (cprng_fast32() & \ ((MAX_RANDOM_FACTOR - MIN_RANDOM_FACTOR) * (x >> 10)))) /1000) -TAILQ_HEAD(nd_drhead, nd_defrouter); -struct nd_defrouter { - TAILQ_ENTRY(nd_defrouter) dr_entry; - struct in6_addr rtaddr; - u_char flags; /* flags on RA message */ - u_short rtlifetime; - u_long expire; - struct ifnet *ifp; - int installed; /* is installed into kernel routing table */ -}; - -#define ND_DEFROUTER_LIST_INIT() \ - TAILQ_INIT(&nd_defrouter) -#define ND_DEFROUTER_LIST_FOREACH(dr) \ - TAILQ_FOREACH((dr), &nd_defrouter, dr_entry) -#define ND_DEFROUTER_LIST_FOREACH_SAFE(dr, dr_next) \ - TAILQ_FOREACH_SAFE((dr), &nd_defrouter, dr_entry, (dr_next)) -#define ND_DEFROUTER_LIST_EMPTY() \ - TAILQ_EMPTY(&nd_defrouter) -#define ND_DEFROUTER_LIST_REMOVE(dr) \ - TAILQ_REMOVE(&nd_defrouter, (dr), dr_entry) -#define ND_DEFROUTER_LIST_INSERT_BEFORE(dr, dr_new) \ - TAILQ_INSERT_BEFORE((dr), (dr_new), dr_entry) -#define ND_DEFROUTER_LIST_INSERT_TAIL(dr) \ - TAILQ_INSERT_TAIL(&nd_defrouter, (dr), dr_entry) -#define ND_DEFROUTER_LIST_FIRST() \ - TAILQ_FIRST(&nd_defrouter) -#define ND_DEFROUTER_LIST_NEXT(dr) \ - TAILQ_NEXT((dr), dr_entry) - -struct nd_prefixctl { - struct ifnet *ndprc_ifp; - - /* prefix */ - struct sockaddr_in6 ndprc_prefix; - u_char ndprc_plen; - - u_int32_t ndprc_vltime; /* advertised valid lifetime */ - u_int32_t ndprc_pltime; /* advertised preferred lifetime */ - - struct prf_ra ndprc_flags; -}; - -#define ndprc_raf ndprc_flags -#define ndprc_raf_onlink ndprc_flags.onlink -#define ndprc_raf_auto ndprc_flags.autonomous -#define ndprc_raf_router ndprc_flags.router - -struct nd_prefix { - struct ifnet *ndpr_ifp; - LIST_ENTRY(nd_prefix) ndpr_entry; - struct sockaddr_in6 ndpr_prefix; /* prefix */ - struct in6_addr ndpr_mask; /* netmask derived from the prefix */ - - u_int32_t ndpr_vltime; /* advertised valid lifetime */ - u_int32_t ndpr_pltime; /* advertised preferred lifetime */ - - time_t ndpr_expire; /* expiration time of the prefix */ - time_t ndpr_preferred; /* preferred time of the prefix */ - time_t ndpr_lastupdate; /* reception time of last advertisement */ - - struct prf_ra ndpr_flags; - u_int32_t ndpr_stateflags; /* actual state flags */ - /* list of routers that advertise the prefix: */ - LIST_HEAD(pr_rtrhead, nd_pfxrouter) ndpr_advrtrs; - u_char ndpr_plen; - int ndpr_refcnt; /* reference couter from addresses */ -}; - -#define ndpr_next ndpr_entry.le_next - -#define ndpr_raf ndpr_flags -#define ndpr_raf_onlink ndpr_flags.onlink -#define ndpr_raf_auto ndpr_flags.autonomous -#define ndpr_raf_router ndpr_flags.router - -#define ND_PREFIX_LIST_FOREACH(pr) \ - LIST_FOREACH((pr), &nd_prefix, ndpr_entry) -#define ND_PREFIX_LIST_FOREACH_SAFE(pr, pr_next) \ - LIST_FOREACH_SAFE((pr), &nd_prefix, ndpr_entry, (pr_next)) -#define ND_PREFIX_LIST_REMOVE(pr) \ - LIST_REMOVE((pr), ndpr_entry) -#define ND_PREFIX_LIST_INSERT_HEAD(pr) \ - LIST_INSERT_HEAD(&nd_prefix, (pr), ndpr_entry) - -/* - * Message format for use in obtaining information about prefixes - * from inet6 sysctl function - */ -struct inet6_ndpr_msghdr { - u_short inpm_msglen; /* to skip over non-understood messages */ - u_char inpm_version; /* future binary compatibility */ - u_char inpm_type; /* message type */ - struct in6_addr inpm_prefix; - u_long prm_vltim; - u_long prm_pltime; - u_long prm_expire; - u_long prm_preferred; - struct in6_prflags prm_flags; - u_short prm_index; /* index for associated ifp */ - u_char prm_plen; /* length of prefix in bits */ -}; - -#define prm_raf_onlink prm_flags.prf_ra.onlink -#define prm_raf_auto prm_flags.prf_ra.autonomous - -#define prm_statef_onlink prm_flags.prf_state.onlink - -#define prm_rrf_decrvalid prm_flags.prf_rr.decrvalid -#define prm_rrf_decrprefd prm_flags.prf_rr.decrprefd - -struct nd_pfxrouter { - LIST_ENTRY(nd_pfxrouter) pfr_entry; - struct nd_defrouter *router; -}; - -LIST_HEAD(nd_prhead, nd_prefix); - #include MALLOC_DECLARE(M_IP6NDP); @@ -367,8 +135,6 @@ extern int nd6_useloopback; extern int nd6_maxnudhint; extern int nd6_gctimer; -extern struct nd_drhead nd_defrouter; -extern struct nd_prhead nd_prefix; extern int nd6_debug; #define nd6log(level, fmt, args...) \ @@ -382,13 +148,6 @@ #define ND6_ASSERT_WLOCK() KASSERT(rw_write_held(&nd6_lock)) #define ND6_ASSERT_LOCK() KASSERT(rw_lock_held(&nd6_lock)) -/* nd6_rtr.c */ -extern int ip6_desync_factor; /* seconds */ -extern u_int32_t ip6_temp_preferred_lifetime; /* seconds */ -extern u_int32_t ip6_temp_valid_lifetime; /* seconds */ -extern int ip6_temp_regen_advance; /* seconds */ -extern int nd6_numroutes; - union nd_opts { struct nd_opt_hdr *nd_opt_array[16]; /* max = ND_OPT_NONCE */ struct { @@ -441,7 +200,6 @@ void nd6_setmtu(struct ifnet *); void nd6_llinfo_settimer(struct llentry *, time_t); void nd6_purge(struct ifnet *, struct in6_ifextra *); -void nd6_assert_purged(struct ifnet *); void nd6_nud_hint(struct rtentry *); int nd6_resolve(struct ifnet *, const struct rtentry *, struct mbuf *, const struct sockaddr *, uint8_t *, size_t); @@ -465,19 +223,7 @@ void nd6_dad_stop(struct ifaddr *); /* nd6_rtr.c */ -void nd6_rs_input(struct mbuf *, int, int); -void nd6_ra_input(struct mbuf *, int, int); -void nd6_defrouter_reset(void); -void nd6_defrouter_select(void); -void nd6_defrtrlist_del(struct nd_defrouter *, struct in6_ifextra *); -void nd6_prefix_unref(struct nd_prefix *); -void nd6_prelist_remove(struct nd_prefix *); -void nd6_invalidate_prefix(struct nd_prefix *); -void nd6_pfxlist_onlink_check(void); -struct nd_defrouter *nd6_defrouter_lookup(const struct in6_addr *, struct ifnet *); -void nd6_rt_flush(struct in6_addr *, struct ifnet *); -int in6_tmpifadd(const struct in6_ifaddr *, int, int); -bool nd6_accepts_rtadv(const struct nd_ifinfo *); +void nd6_rtr_cache(struct mbuf *, int, int, int); #endif /* _KERNEL */ diff -r 80f27e12612b sys/netinet6/nd6_nbr.c --- a/sys/netinet6/nd6_nbr.c Tue Apr 21 12:23:13 2020 +0000 +++ b/sys/netinet6/nd6_nbr.c Wed Apr 22 00:54:02 2020 +0100 @@ -611,7 +611,6 @@ struct llentry *ln = NULL; union nd_opts ndopts; struct sockaddr_in6 ssin6; - bool checklink = false; struct psref psref; struct psref psref_ia; char ip6buf[INET6_ADDRSTRLEN], ip6buf2[INET6_ADDRSTRLEN]; @@ -760,14 +759,6 @@ ln->ln_state = ND6_LLINFO_STALE; nd6_llinfo_settimer(ln, nd6_gctimer * hz); } - if ((ln->ln_router = is_router) != 0) { - /* - * This means a router's state has changed from - * non-reachable to probably reachable, and might - * affect the status of associated prefixes.. - */ - checklink = true; - } } else { bool llchange; @@ -848,32 +839,6 @@ } } } - - if (ln->ln_router && !is_router) { - /* - * The peer dropped the router flag. - * Remove the sender from the Default Router List and - * update the Destination Cache entries. - */ - const struct in6_addr *in6 = &ln->r_l3addr.addr6; - struct nd_defrouter *dr; - - ND6_WLOCK(); - dr = nd6_defrouter_lookup(in6, ln->lle_tbl->llt_ifp); - if (dr) - nd6_defrtrlist_del(dr, NULL); - else if (!ip6_forwarding) { - /* - * Even if the neighbor is not in the default - * router list, the neighbor may be used - * as a next hop for some destinations - * (e.g. redirect case). So we must - * call nd6_rt_flush explicitly. - */ - nd6_rt_flush(&ip6->ip6_src, ln->lle_tbl->llt_ifp); - } - ND6_UNLOCK(); - } ln->ln_router = is_router; } /* @@ -895,12 +860,6 @@ if (ln != NULL) LLE_WUNLOCK(ln); - if (checklink) { - ND6_WLOCK(); - nd6_pfxlist_onlink_check(); - ND6_UNLOCK(); - } - m_put_rcvif_psref(ifp, &psref); m_freem(m); return; diff -r 80f27e12612b sys/netinet6/nd6_rtr.c --- a/sys/netinet6/nd6_rtr.c Tue Apr 21 12:23:13 2020 +0000 +++ b/sys/netinet6/nd6_rtr.c Wed Apr 22 00:54:02 2020 +0100 @@ -37,111 +37,29 @@ #include "opt_net_mpsafe.h" #endif -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include -#include #include -#include -#include #include #include -#include #include -#include #include #include #include -#include - -static int rtpref(struct nd_defrouter *); -static struct nd_defrouter *defrtrlist_update(struct nd_defrouter *); -static int prelist_update(struct nd_prefixctl *, struct nd_defrouter *, - struct mbuf *, int); -static struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int, struct psref *); -static struct nd_pfxrouter *pfxrtr_lookup(struct nd_prefix *, - struct nd_defrouter *); -static void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *); -static void pfxrtr_del(struct nd_pfxrouter *); -static struct nd_pfxrouter *find_pfxlist_reachable_router - (struct nd_prefix *); - -static void defrouter_addreq(struct nd_defrouter *); -static void defrouter_delreq(struct nd_defrouter *); - -static int in6_init_prefix_ltimes(struct nd_prefix *); -static void in6_init_address_ltimes(struct nd_prefix *, - struct in6_addrlifetime *); -static void purge_detached(struct ifnet *); - -static int rt6_deleteroute_matcher(struct rtentry *, void *); - -static int nd6_prelist_add(struct nd_prefixctl *, struct nd_defrouter *, - struct nd_prefix **); -static int nd6_prefix_onlink(struct nd_prefix *); -static int nd6_prefix_offlink(struct nd_prefix *); -static struct nd_prefix *nd6_prefix_lookup(struct nd_prefixctl *); - -extern int nd6_recalc_reachtm_interval; - -int ip6_use_tempaddr = 0; - -int ip6_desync_factor; -u_int32_t ip6_temp_preferred_lifetime = DEF_TEMP_PREFERRED_LIFETIME; -u_int32_t ip6_temp_valid_lifetime = DEF_TEMP_VALID_LIFETIME; -int ip6_temp_regen_advance = TEMPADDR_REGEN_ADVANCE; - -int nd6_numroutes = 0; - -/* RTPREF_MEDIUM has to be 0! */ -#define RTPREF_HIGH 1 -#define RTPREF_MEDIUM 0 -#define RTPREF_LOW (-1) -#define RTPREF_RESERVED (-2) -#define RTPREF_INVALID (-3) /* internal */ - -static inline bool -nd6_is_llinfo_probreach(struct nd_defrouter *dr) -{ - struct llentry *ln = NULL; - - ln = nd6_lookup(&dr->rtaddr, dr->ifp, false); - if (ln == NULL) - return false; - - if (!ND6_IS_LLINFO_PROBREACH(ln)) { - LLE_RUNLOCK(ln); - return false; - } - - LLE_RUNLOCK(ln); - return true; -} /* - * Receive Router Solicitation Message - just for routers. - * Router solicitation/advertisement is mostly managed by a userland program - * (rtadvd) so here we have no function like nd6_ra_output(). - * - * Based on RFC 2461 + * Cache the source link layer address of Router Advertisement + * and Solicition messages. */ void -nd6_rs_input(struct mbuf *m, int off, int icmp6len) +nd6_rtr_cache(struct mbuf *m, int off, int icmp6len, int icmp6_type) { struct ifnet *ifp; - struct nd_ifinfo *ndi; struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct nd_router_solicit *nd_rs; + struct nd_router_advert *nd_ra; struct in6_addr saddr6 = ip6->ip6_src; char *lladdr = NULL; int lladdrlen = 0; @@ -153,12 +71,6 @@ if (ifp == NULL) goto freeit; - ndi = ND_IFINFO(ifp); - - /* If I'm not a router, ignore it. */ - if (nd6_accepts_rtadv(ndi) || !ip6_forwarding) - goto freeit; - /* Sanity checks */ if (ip6->ip6_hlim != 255) { nd6log(LOG_ERR, "invalid hlim (%d) from %s to %s on %s\n", @@ -167,22 +79,46 @@ goto bad; } - /* - * Don't update the neighbor cache, if src = ::. - * This indicates that the src has no IP address assigned yet. - */ - if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) - goto freeit; + switch (icmp6_type) { + case ND_ROUTER_SOLICIT: + /* + * Don't update the neighbor cache, if src = ::. + * This indicates that the src has no IP address assigned yet. + */ + if (IN6_IS_ADDR_UNSPECIFIED(&saddr6)) + goto freeit; + + IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, + icmp6len); + if (nd_rs == NULL) { + ICMP6_STATINC(ICMP6_STAT_TOOSHORT); + m_put_rcvif_psref(ifp, &psref); + return; + } - IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len); - if (nd_rs == NULL) { - ICMP6_STATINC(ICMP6_STAT_TOOSHORT); - m_put_rcvif_psref(ifp, &psref); - return; + icmp6len -= sizeof(*nd_rs); + nd6_option_init(nd_rs + 1, icmp6len, &ndopts); + break; + case ND_ROUTER_ADVERT: + if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { + nd6log(LOG_ERR, "src %s is not link-local\n", + IN6_PRINT(ip6bufs, &saddr6)); + goto bad; + } + + IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, + icmp6len); + if (nd_ra == NULL) { + ICMP6_STATINC(ICMP6_STAT_TOOSHORT); + m_put_rcvif_psref(ifp, &psref); + return; + } + + icmp6len -= sizeof(*nd_ra); + nd6_option_init(nd_ra + 1, icmp6len, &ndopts); + break; } - icmp6len -= sizeof(*nd_rs); - nd6_option_init(nd_rs + 1, icmp6len, &ndopts); if (nd6_options(&ndopts) < 0) { nd6log(LOG_INFO, "invalid ND option, ignored\n"); /* nd6_options have incremented stats */ @@ -196,2077 +132,24 @@ if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { nd6log(LOG_INFO, "lladdrlen mismatch for %s " - "(if %d, RS packet %d)\n", + "(if %d, %s packet %d)\n", IN6_PRINT(ip6bufs, &saddr6), - ifp->if_addrlen, lladdrlen - 2); - goto bad; - } - - nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0); - - freeit: - m_put_rcvif_psref(ifp, &psref); - m_freem(m); - return; - - bad: - ICMP6_STATINC(ICMP6_STAT_BADRS); - m_put_rcvif_psref(ifp, &psref); - m_freem(m); -} - -/* - * Receive Router Advertisement Message. - * - * Based on RFC 2461 - * TODO: on-link bit on prefix information - * TODO: ND_RA_FLAG_{OTHER,MANAGED} processing - */ -void -nd6_ra_input(struct mbuf *m, int off, int icmp6len) -{ - struct ifnet *ifp; - struct nd_ifinfo *ndi; - struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - struct nd_router_advert *nd_ra; - struct in6_addr saddr6 = ip6->ip6_src; - int mcast = 0; - union nd_opts ndopts; - struct nd_defrouter *dr; - struct psref psref; - char ip6buf[INET6_ADDRSTRLEN], ip6buf2[INET6_ADDRSTRLEN]; - - ifp = m_get_rcvif_psref(m, &psref); - if (ifp == NULL) - goto freeit; - - ndi = ND_IFINFO(ifp); - /* - * We only accept RAs when the system-wide variable allows the - * acceptance, and the per-interface variable allows RAs on the - * receiving interface. - */ - if (!nd6_accepts_rtadv(ndi)) - goto freeit; - - if (ip6->ip6_hlim != 255) { - nd6log(LOG_ERR, "invalid hlim (%d) from %s to %s on %s\n", - ip6->ip6_hlim, IN6_PRINT(ip6buf, &ip6->ip6_src), - IN6_PRINT(ip6buf2, &ip6->ip6_dst), if_name(ifp)); - goto bad; - } - - if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) { - nd6log(LOG_ERR, "src %s is not link-local\n", - IN6_PRINT(ip6buf, &saddr6)); + ifp->if_addrlen, + icmp6_type == ND_ROUTER_SOLICIT ? "RS" : "RA", + lladdrlen - 2); goto bad; } - IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len); - if (nd_ra == NULL) { - ICMP6_STATINC(ICMP6_STAT_TOOSHORT); - m_put_rcvif_psref(ifp, &psref); - return; - } - - icmp6len -= sizeof(*nd_ra); - nd6_option_init(nd_ra + 1, icmp6len, &ndopts); - if (nd6_options(&ndopts) < 0) { - nd6log(LOG_INFO, "invalid ND option, ignored\n"); - /* nd6_options have incremented stats */ - goto freeit; - } - - { - struct nd_defrouter drtr; - u_int32_t advreachable = nd_ra->nd_ra_reachable; - - /* remember if this is a multicasted advertisement */ - if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) - mcast = 1; - - memset(&drtr, 0, sizeof(drtr)); - drtr.rtaddr = saddr6; - drtr.flags = nd_ra->nd_ra_flags_reserved; - drtr.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime); - drtr.expire = time_uptime + drtr.rtlifetime; - drtr.ifp = ifp; - /* unspecified or not? (RFC 2461 6.3.4) */ - if (advreachable) { - NTOHL(advreachable); - if (advreachable <= MAX_REACHABLE_TIME && - ndi->basereachable != advreachable) { - ndi->basereachable = advreachable; - ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable); - ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */ - } - } - if (nd_ra->nd_ra_retransmit) - ndi->retrans = ntohl(nd_ra->nd_ra_retransmit); - if (nd_ra->nd_ra_curhoplimit) { - if (ndi->chlim < nd_ra->nd_ra_curhoplimit) - ndi->chlim = nd_ra->nd_ra_curhoplimit; - else if (ndi->chlim != nd_ra->nd_ra_curhoplimit) - log(LOG_ERR, "nd_ra_input: lower CurHopLimit sent from " - "%s on %s (current=%d, received=%d), ignored\n", - IN6_PRINT(ip6buf, &ip6->ip6_src), - if_name(ifp), ndi->chlim, nd_ra->nd_ra_curhoplimit); - } - IFNET_LOCK(ifp); - ND6_WLOCK(); - dr = defrtrlist_update(&drtr); - } - - /* - * prefix - */ - if (ndopts.nd_opts_pi) { - struct nd_opt_hdr *pt; - struct nd_opt_prefix_info *pi = NULL; - struct nd_prefixctl prc; - - for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi; - pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end; - pt = (struct nd_opt_hdr *)((char *)pt + - (pt->nd_opt_len << 3))) { - if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION) - continue; - pi = (struct nd_opt_prefix_info *)pt; - - if (pi->nd_opt_pi_len != 4) { - nd6log(LOG_INFO, "invalid option " - "len %d for prefix information option, " - "ignored\n", pi->nd_opt_pi_len); - continue; - } - - if (128 < pi->nd_opt_pi_prefix_len) { - nd6log(LOG_INFO, "invalid prefix " - "len %d for prefix information option, " - "ignored\n", pi->nd_opt_pi_prefix_len); - continue; - } + nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, icmp6_type, 0); - if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) - || IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) { - nd6log(LOG_INFO, - "invalid prefix %s, ignored\n", - IN6_PRINT(ip6buf, &pi->nd_opt_pi_prefix)); - continue; - } - - memset(&prc, 0, sizeof(prc)); - sockaddr_in6_init(&prc.ndprc_prefix, - &pi->nd_opt_pi_prefix, 0, 0, 0); - prc.ndprc_ifp = ifp; - - prc.ndprc_raf_onlink = (pi->nd_opt_pi_flags_reserved & - ND_OPT_PI_FLAG_ONLINK) ? 1 : 0; - prc.ndprc_raf_auto = (pi->nd_opt_pi_flags_reserved & - ND_OPT_PI_FLAG_AUTO) ? 1 : 0; - prc.ndprc_plen = pi->nd_opt_pi_prefix_len; - prc.ndprc_vltime = ntohl(pi->nd_opt_pi_valid_time); - prc.ndprc_pltime = ntohl(pi->nd_opt_pi_preferred_time); - - (void)prelist_update(&prc, dr, m, mcast); - } - } - ND6_UNLOCK(); - IFNET_UNLOCK(ifp); - - /* - * MTU - */ - if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) { - u_long mtu; - u_long maxmtu; - - mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); - - /* lower bound */ - if (mtu < IPV6_MMTU) { - nd6log(LOG_INFO, "bogus mtu option " - "mtu=%lu sent from %s, ignoring\n", - mtu, IN6_PRINT(ip6buf, &ip6->ip6_src)); - goto skip; - } - - /* upper bound */ - maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu) - ? ndi->maxmtu : ifp->if_mtu; - if (mtu <= maxmtu) { - int change = (ndi->linkmtu != mtu); - - ndi->linkmtu = mtu; - if (change) /* in6_maxmtu may change */ - in6_setmaxmtu(); - } else { - nd6log(LOG_INFO, - "bogus mtu mtu=%lu sent from %s; " - "exceeds maxmtu %lu, ignoring\n", - mtu, IN6_PRINT(ip6buf, &ip6->ip6_src), maxmtu); - } - } - - skip: - - /* - * Source link layer address - */ - { - char *lladdr = NULL; - int lladdrlen = 0; - - if (ndopts.nd_opts_src_lladdr) { - lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1); - lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3; - } - - if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) { - nd6log(LOG_INFO, "lladdrlen mismatch for %s " - "(if %d, RA packet %d)\n", IN6_PRINT(ip6buf, &saddr6), - ifp->if_addrlen, lladdrlen - 2); - goto bad; - } - - nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0); - - /* - * Installing a link-layer address might change the state of the - * router's neighbor cache, which might also affect our on-link - * detection of adveritsed prefixes. - */ - ND6_WLOCK(); - nd6_pfxlist_onlink_check(); - ND6_UNLOCK(); - } - - freeit: +freeit: m_put_rcvif_psref(ifp, &psref); m_freem(m); return; - bad: - ICMP6_STATINC(ICMP6_STAT_BADRA); +bad: + ICMP6_STATINC(icmp6_type == ND_ROUTER_SOLICIT ? + ICMP6_STAT_BADRS : ICMP6_STAT_BADRA); m_put_rcvif_psref(ifp, &psref); m_freem(m); } - -/* - * default router list processing sub routines - */ -static void -defrouter_addreq(struct nd_defrouter *newdr) -{ - union { - struct sockaddr_in6 sin6; - struct sockaddr sa; - } def, mask, gate; -#ifndef NET_MPSAFE - int s; -#endif - int error; - - memset(&def, 0, sizeof(def)); - memset(&mask, 0, sizeof(mask)); - memset(&gate, 0,sizeof(gate)); /* for safety */ - - def.sin6.sin6_len = mask.sin6.sin6_len = gate.sin6.sin6_len = - sizeof(struct sockaddr_in6); - def.sin6.sin6_family = mask.sin6.sin6_family = gate.sin6.sin6_family = AF_INET6; - gate.sin6.sin6_addr = newdr->rtaddr; -#ifndef SCOPEDROUTING - gate.sin6.sin6_scope_id = 0; /* XXX */ -#endif - -#ifndef NET_MPSAFE - s = splsoftnet(); -#endif - error = rtrequest_newmsg(RTM_ADD, &def.sa, &gate.sa, &mask.sa, - RTF_GATEWAY); - if (error == 0) { - nd6_numroutes++; - newdr->installed = 1; - } else { - char ip6buf[INET6_ADDRSTRLEN]; - log(LOG_ERR, "defrouter_addreq: " - "error %d adding default router %s on %s\n", - error, IN6_PRINT(ip6buf, &newdr->rtaddr), newdr->ifp->if_xname); - } -#ifndef NET_MPSAFE - splx(s); -#endif - return; -} - -struct nd_defrouter * -nd6_defrouter_lookup(const struct in6_addr *addr, struct ifnet *ifp) -{ - struct nd_defrouter *dr; - - ND6_ASSERT_LOCK(); - - ND_DEFROUTER_LIST_FOREACH(dr) { - if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) - break; - } - - return dr; /* search failed */ -} - -void -nd6_defrtrlist_del(struct nd_defrouter *dr, struct in6_ifextra *ext) -{ - struct nd_defrouter *deldr = NULL; - struct nd_prefix *pr; - struct nd_ifinfo *ndi; - - ND6_ASSERT_WLOCK(); - - if (ext == NULL) - ext = dr->ifp->if_afdata[AF_INET6]; - - /* detach already in progress, can not do anything */ - if (ext == NULL) - return; - - ndi = ext->nd_ifinfo; - - /* - * Flush all the routing table entries that use the router - * as a next hop. - */ - /* XXX: better condition? */ - if (!ip6_forwarding && nd6_accepts_rtadv(ndi)) - nd6_rt_flush(&dr->rtaddr, dr->ifp); - - if (dr->installed) { - deldr = dr; - defrouter_delreq(dr); - } - ND_DEFROUTER_LIST_REMOVE(dr); - - /* - * Also delete all the pointers to the router in each prefix lists. - */ - ND_PREFIX_LIST_FOREACH(pr) { - struct nd_pfxrouter *pfxrtr; - if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) - pfxrtr_del(pfxrtr); - } - nd6_pfxlist_onlink_check(); - - /* - * If the router is the primary one, choose a new one. - * Note that nd6_defrouter_select() will remove the current gateway - * from the routing table. - */ - if (deldr) - nd6_defrouter_select(); - - ext->ndefrouters--; - if (ext->ndefrouters < 0) { - log(LOG_WARNING, "nd6_defrtrlist_del: negative count on %s\n", - dr->ifp->if_xname); - } - - free(dr, M_IP6NDP); -} - -/* - * Remove the default route for a given router. - * This is just a subroutine function for nd6_defrouter_select(), and should - * not be called from anywhere else. - */ -static void -defrouter_delreq(struct nd_defrouter *dr) -{ - union { - struct sockaddr_in6 sin6; - struct sockaddr sa; - } def, mask, gw; - int error; - - memset(&def, 0, sizeof(def)); - memset(&mask, 0, sizeof(mask)); - memset(&gw, 0, sizeof(gw)); /* for safety */ - - def.sin6.sin6_len = mask.sin6.sin6_len = gw.sin6.sin6_len = - sizeof(struct sockaddr_in6); - def.sin6.sin6_family = mask.sin6.sin6_family = gw.sin6.sin6_family = AF_INET6; - gw.sin6.sin6_addr = dr->rtaddr; -#ifndef SCOPEDROUTING - gw.sin6.sin6_scope_id = 0; /* XXX */ -#endif - - error = rtrequest_newmsg(RTM_DELETE, &def.sa, &gw.sa, &mask.sa, - RTF_GATEWAY); - if (error == 0) { - nd6_numroutes--; - dr->installed = 0; - } else { - char ip6buf[INET6_ADDRSTRLEN]; - log(LOG_ERR, "defrouter_delreq: " - "error %d deleting default router %s on %s\n", - error, IN6_PRINT(ip6buf, &dr->rtaddr), dr->ifp->if_xname); - } -} - -/* - * remove all default routes from default router list - */ -void -nd6_defrouter_reset(void) -{ - struct nd_defrouter *dr; - - ND6_ASSERT_WLOCK(); - - ND_DEFROUTER_LIST_FOREACH(dr) - defrouter_delreq(dr); - - /* - * XXX should we also nuke any default routers in the kernel, by - * going through them by rtalloc1()? - */ -} - -/* - * Default Router Selection according to Section 6.3.6 of RFC 2461 and - * draft-ietf-ipngwg-router-selection: - * 1) Routers that are reachable or probably reachable should be preferred. - * If we have more than one (probably) reachable router, prefer ones - * with the highest router preference. - * 2) When no routers on the list are known to be reachable or - * probably reachable, routers SHOULD be selected in a round-robin - * fashion, regardless of router preference values. - * 3) If the Default Router List is empty, assume that all - * destinations are on-link. - * - * We assume nd_defrouter is sorted by router preference value. - * Since the code below covers both with and without router preference cases, - * we do not need to classify the cases by ifdef. - * - * At this moment, we do not try to install more than one default router, - * even when the multipath routing is available, because we're not sure about - * the benefits for stub hosts comparing to the risk of making the code - * complicated and the possibility of introducing bugs. - */ -void -nd6_defrouter_select(void) -{ - struct nd_ifinfo *ndi; - struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL; - - ND6_ASSERT_WLOCK(); - - /* - * This function should be called only when acting as an autoconfigured - * host. Although the remaining part of this function is not effective - * if the node is not an autoconfigured host, we explicitly exclude - * such cases here for safety. - */ - if (ip6_forwarding) { - nd6log(LOG_WARNING, "called unexpectedly (forwarding=%d, " - "accept_rtadv=%d)\n", ip6_forwarding, ip6_accept_rtadv); - return; - } - - /* - * Let's handle easy case (3) first: - * If default router list is empty, there's nothing to be done. - */ - if (ND_DEFROUTER_LIST_EMPTY()) - return; - - /* - * Search for a (probably) reachable router from the list. - * We just pick up the first reachable one (if any), assuming that - * the ordering rule of the list described in defrtrlist_update(). - */ - ND_DEFROUTER_LIST_FOREACH(dr) { - if (dr->installed && !installed_dr) - installed_dr = dr; - else if (dr->installed && installed_dr) { - /* this should not happen. warn for diagnosis. */ - log(LOG_ERR, "nd6_defrouter_select: more than one router" - " is installed\n"); - } - - ndi = ND_IFINFO(dr->ifp); - if (!nd6_accepts_rtadv(ndi)) - continue; - - if (selected_dr == NULL && - nd6_is_llinfo_probreach(dr)) - selected_dr = dr; - } - /* - * If none of the default routers was found to be reachable, - * round-robin the list regardless of preference. - * Otherwise, if we have an installed router, check if the selected - * (reachable) router should really be preferred to the installed one. - * We only prefer the new router when the old one is not reachable - * or when the new one has a really higher preference value. - */ - if (selected_dr == NULL) { - if (installed_dr == NULL || - ND_DEFROUTER_LIST_NEXT(installed_dr) == NULL) - selected_dr = ND_DEFROUTER_LIST_FIRST(); - else - selected_dr = ND_DEFROUTER_LIST_NEXT(installed_dr); - } else if (installed_dr && - nd6_is_llinfo_probreach(installed_dr) && - rtpref(selected_dr) <= rtpref(installed_dr)) { - selected_dr = installed_dr; - } - - /* - * If the selected router is different than the installed one, - * remove the installed router and install the selected one. - * Note that the selected router is never NULL here. - */ - if (installed_dr != selected_dr) { - if (installed_dr) - defrouter_delreq(installed_dr); - defrouter_addreq(selected_dr); - } - - return; -} - -/* - * for default router selection - * regards router-preference field as a 2-bit signed integer - */ -static int -rtpref(struct nd_defrouter *dr) -{ - switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) { - case ND_RA_FLAG_RTPREF_HIGH: - return (RTPREF_HIGH); - case ND_RA_FLAG_RTPREF_MEDIUM: - case ND_RA_FLAG_RTPREF_RSV: - return (RTPREF_MEDIUM); - case ND_RA_FLAG_RTPREF_LOW: - return (RTPREF_LOW); - default: - /* - * This case should never happen. If it did, it would mean a - * serious bug of kernel internal. We thus always bark here. - * Or, can we even panic? - */ - log(LOG_ERR, "rtpref: impossible RA flag %x\n", dr->flags); - return (RTPREF_INVALID); - } - /* NOTREACHED */ -} - -static struct nd_defrouter * -defrtrlist_update(struct nd_defrouter *newdr) -{ - struct nd_defrouter *dr, *n, *ret = NULL; - struct in6_ifextra *ext = newdr->ifp->if_afdata[AF_INET6]; - - ND6_ASSERT_WLOCK(); - - if ((dr = nd6_defrouter_lookup(&newdr->rtaddr, newdr->ifp)) != NULL) { - /* entry exists */ - if (newdr->rtlifetime == 0) { - nd6_defrtrlist_del(dr, ext); - dr = NULL; - } else { - int oldpref = rtpref(dr); - - /* override */ - dr->flags = newdr->flags; /* xxx flag check */ - dr->rtlifetime = newdr->rtlifetime; - dr->expire = newdr->expire; - - /* - * If the preference does not change, there's no need - * to sort the entries. - */ - if (rtpref(newdr) == oldpref) { - ret = dr; - goto out; - } - - /* - * preferred router may be changed, so relocate - * this router. - * XXX: calling TAILQ_REMOVE directly is a bad manner. - * However, since nd6_defrtrlist_del() has many side - * effects, we intentionally do so here. - * nd6_defrouter_select() below will handle routing - * changes later. - */ - ND_DEFROUTER_LIST_REMOVE(dr); - n = dr; - goto insert; - } - ret = dr; - goto out; - } - - if (ip6_maxifdefrouters >= 0 && ext->ndefrouters >= ip6_maxifdefrouters) - goto out; - - /* entry does not exist */ - if (newdr->rtlifetime == 0) - goto out; - - if (ip6_rtadv_maxroutes <= nd6_numroutes) { - ICMP6_STATINC(ICMP6_STAT_DROPPED_RAROUTE); - goto out; - } - - n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT); - if (n == NULL) - goto out; - memset(n, 0, sizeof(*n)); - *n = *newdr; - -insert: - /* - * Insert the new router in the Default Router List; - * The Default Router List should be in the descending order - * of router-preference. Routers with the same preference are - * sorted in the arriving time order. - */ - - /* insert at the end of the group */ - ND_DEFROUTER_LIST_FOREACH(dr) { - if (rtpref(n) > rtpref(dr)) - break; - } - if (dr) - ND_DEFROUTER_LIST_INSERT_BEFORE(dr, n); - else - ND_DEFROUTER_LIST_INSERT_TAIL(n); - - nd6_defrouter_select(); - - ext->ndefrouters++; - - ret = n; -out: - return ret; -} - -static struct nd_pfxrouter * -pfxrtr_lookup(struct nd_prefix *pr, struct nd_defrouter *dr) -{ - struct nd_pfxrouter *search; - - ND6_ASSERT_LOCK(); - - LIST_FOREACH(search, &pr->ndpr_advrtrs, pfr_entry) { - if (search->router == dr) - break; - } - - return (search); -} - -static void -pfxrtr_add(struct nd_prefix *pr, struct nd_defrouter *dr) -{ - struct nd_pfxrouter *newpfr; - - ND6_ASSERT_WLOCK(); - - newpfr = malloc(sizeof(*newpfr), M_IP6NDP, M_NOWAIT|M_ZERO); - if (newpfr == NULL) - return; - newpfr->router = dr; - - LIST_INSERT_HEAD(&pr->ndpr_advrtrs, newpfr, pfr_entry); - - nd6_pfxlist_onlink_check(); -} - -static void -pfxrtr_del(struct nd_pfxrouter *pfr) -{ - LIST_REMOVE(pfr, pfr_entry); - free(pfr, M_IP6NDP); -} - -static struct nd_prefix * -nd6_prefix_lookup(struct nd_prefixctl *key) -{ - struct nd_prefix *search; - - ND_PREFIX_LIST_FOREACH(search) { - if (key->ndprc_ifp == search->ndpr_ifp && - key->ndprc_plen == search->ndpr_plen && - in6_are_prefix_equal(&key->ndprc_prefix.sin6_addr, - &search->ndpr_prefix.sin6_addr, key->ndprc_plen)) { - break; - } - } - - return (search); -} - -static void -purge_detached(struct ifnet *ifp) -{ - struct nd_prefix *pr, *pr_next; - struct in6_ifaddr *ia; - struct ifaddr *ifa, *ifa_next; - -restart: - ND6_ASSERT_WLOCK(); - - ND_PREFIX_LIST_FOREACH_SAFE(pr, pr_next) { - int s; - - /* - * This function is called when we need to make more room for - * new prefixes rather than keeping old, possibly stale ones. - * Detached prefixes would be a good candidate; if all routers - * that advertised the prefix expired, the prefix is also - * probably stale. - */ - if (pr->ndpr_ifp != ifp || - IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr) || - ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && - !LIST_EMPTY(&pr->ndpr_advrtrs))) - continue; - - s = pserialize_read_enter(); - for (ifa = IFADDR_READER_FIRST(ifp); ifa; ifa = ifa_next) { - ifa_next = IFADDR_READER_NEXT(ifa); - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - ia = (struct in6_ifaddr *)ifa; - if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == - IN6_IFF_AUTOCONF && ia->ia6_ndpr == pr) { - pserialize_read_exit(s); - ND6_UNLOCK(); - - /* in6_purgeaddr may destroy pr. */ - in6_purgeaddr(ifa); - - ND6_WLOCK(); - goto restart; - } - } - pserialize_read_exit(s); - - KASSERTMSG(pr->ndpr_refcnt == 0, "ndpr_refcnt=%d", - pr->ndpr_refcnt); - nd6_prelist_remove(pr); - } -} - -static int -nd6_prelist_add(struct nd_prefixctl *prc, struct nd_defrouter *dr, - struct nd_prefix **newp) -{ - struct nd_prefix *newpr = NULL; - int i; - int error; - struct in6_ifextra *ext = prc->ndprc_ifp->if_afdata[AF_INET6]; - - ND6_ASSERT_WLOCK(); - - if (ip6_maxifprefixes >= 0) { - if (ext->nprefixes >= ip6_maxifprefixes / 2) - purge_detached(prc->ndprc_ifp); - if (ext->nprefixes >= ip6_maxifprefixes) - return ENOMEM; - } - - error = 0; - newpr = malloc(sizeof(*newpr), M_IP6NDP, M_NOWAIT|M_ZERO); - if (newpr == NULL) - return ENOMEM; - newpr->ndpr_ifp = prc->ndprc_ifp; - newpr->ndpr_prefix = prc->ndprc_prefix; - newpr->ndpr_plen = prc->ndprc_plen; - newpr->ndpr_vltime = prc->ndprc_vltime; - newpr->ndpr_pltime = prc->ndprc_pltime; - newpr->ndpr_flags = prc->ndprc_flags; - if ((error = in6_init_prefix_ltimes(newpr)) != 0) { - free(newpr, M_IP6NDP); - return(error); - } - newpr->ndpr_lastupdate = time_uptime; - if (newp != NULL) - *newp = newpr; - - /* initialization */ - LIST_INIT(&newpr->ndpr_advrtrs); - in6_prefixlen2mask(&newpr->ndpr_mask, newpr->ndpr_plen); - /* make prefix in the canonical form */ - for (i = 0; i < 4; i++) { - newpr->ndpr_prefix.sin6_addr.s6_addr32[i] &= - newpr->ndpr_mask.s6_addr32[i]; - } - - /* link ndpr_entry to nd_prefix list */ - ND_PREFIX_LIST_INSERT_HEAD(newpr); - - /* ND_OPT_PI_FLAG_ONLINK processing */ - if (newpr->ndpr_raf_onlink) { - int e; - - if ((e = nd6_prefix_onlink(newpr)) != 0) { - char ip6buf[INET6_ADDRSTRLEN]; - nd6log(LOG_ERR, "failed to make " - "the prefix %s/%d on-link on %s (errno=%d)\n", - IN6_PRINT(ip6buf, &prc->ndprc_prefix.sin6_addr), - prc->ndprc_plen, if_name(prc->ndprc_ifp), e); - /* proceed anyway. XXX: is it correct? */ - } - } - - if (dr) - pfxrtr_add(newpr, dr); - - ext->nprefixes++; - - return 0; -} - -void -nd6_prefix_unref(struct nd_prefix *pr) -{ - - ND6_WLOCK(); - pr->ndpr_refcnt--; - if (pr->ndpr_refcnt == 0) - nd6_prelist_remove(pr); - ND6_UNLOCK(); -} - -void -nd6_invalidate_prefix(struct nd_prefix *pr) -{ - int e; - - ND6_ASSERT_WLOCK(); - - /* make sure to invalidate the prefix until it is really freed. */ - pr->ndpr_vltime = 0; - pr->ndpr_pltime = 0; -#if 0 - /* - * Though these flags are now meaningless, we'd rather keep the value - * not to confuse users when executing "ndp -p". - */ - pr->ndpr_raf_onlink = 0; - pr->ndpr_raf_auto = 0; -#endif - if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 && - (e = nd6_prefix_offlink(pr)) != 0) { - char ip6buf[INET6_ADDRSTRLEN]; - nd6log(LOG_ERR, - "failed to make %s/%d offlink on %s, errno=%d\n", - IN6_PRINT(ip6buf, &pr->ndpr_prefix.sin6_addr), - pr->ndpr_plen, if_name(pr->ndpr_ifp), e); - /* what should we do? */ - } -} - -void -nd6_prelist_remove(struct nd_prefix *pr) -{ - struct nd_pfxrouter *pfr, *next; - struct in6_ifextra *ext = pr->ndpr_ifp->if_afdata[AF_INET6]; - - ND6_ASSERT_WLOCK(); - KASSERTMSG(pr->ndpr_refcnt == 0, "ndpr_refcnt=%d", pr->ndpr_refcnt); - - nd6_invalidate_prefix(pr); - - /* unlink ndpr_entry from nd_prefix list */ - ND_PREFIX_LIST_REMOVE(pr); - - /* free list of routers that adversed the prefix */ - for (pfr = LIST_FIRST(&pr->ndpr_advrtrs); pfr != NULL; pfr = next) { - next = LIST_NEXT(pfr, pfr_entry); - - free(pfr, M_IP6NDP); - } - - if (ext) { - ext->nprefixes--; - if (ext->nprefixes < 0) { - log(LOG_WARNING, "nd6_prelist_remove: negative count on " - "%s\n", pr->ndpr_ifp->if_xname); - } - } - - free(pr, M_IP6NDP); - - nd6_pfxlist_onlink_check(); -} - -static int -prelist_update(struct nd_prefixctl *newprc, - struct nd_defrouter *dr, /* may be NULL */ - struct mbuf *m, - int mcast) -{ - struct in6_ifaddr *ia6_match = NULL; - struct ifaddr *ifa; - struct ifnet *ifp = newprc->ndprc_ifp; - struct nd_prefix *pr; - int error = 0; - int auth; - struct in6_addrlifetime lt6_tmp; - int ss; - char ip6buf[INET6_ADDRSTRLEN]; - - KASSERT(m != NULL); - ND6_ASSERT_WLOCK(); - - auth = (m->m_flags & M_AUTHIPHDR) ? 1 : 0; - - if ((pr = nd6_prefix_lookup(newprc)) != NULL) { - /* - * nd6_prefix_lookup() ensures that pr and newprc have the same - * prefix on a same interface. - */ - - /* - * Update prefix information. Note that the on-link (L) bit - * and the autonomous (A) bit should NOT be changed from 1 - * to 0. - */ - if (newprc->ndprc_raf_onlink == 1) - pr->ndpr_raf_onlink = 1; - if (newprc->ndprc_raf_auto == 1) - pr->ndpr_raf_auto = 1; - if (newprc->ndprc_raf_onlink) { - pr->ndpr_vltime = newprc->ndprc_vltime; - pr->ndpr_pltime = newprc->ndprc_pltime; - (void)in6_init_prefix_ltimes(pr); /* XXX error case? */ - pr->ndpr_lastupdate = time_uptime; - } - - if (newprc->ndprc_raf_onlink && - (pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { - int e; - - if ((e = nd6_prefix_onlink(pr)) != 0) { - nd6log(LOG_ERR, - "failed to make " - "the prefix %s/%d on-link on %s " - "(errno=%d)\n", - IN6_PRINT(ip6buf, - &pr->ndpr_prefix.sin6_addr), - pr->ndpr_plen, if_name(pr->ndpr_ifp), e); - /* proceed anyway. XXX: is it correct? */ - } - } - - if (dr && pfxrtr_lookup(pr, dr) == NULL) - pfxrtr_add(pr, dr); - } else { - struct nd_prefix *newpr = NULL; - - if (newprc->ndprc_vltime == 0) - goto end; - if (newprc->ndprc_raf_onlink == 0 && newprc->ndprc_raf_auto == 0) - goto end; - - if (ip6_rtadv_maxroutes <= nd6_numroutes) { - ICMP6_STATINC(ICMP6_STAT_DROPPED_RAROUTE); - goto end; - } - - error = nd6_prelist_add(newprc, dr, &newpr); - if (error != 0 || newpr == NULL) { - nd6log(LOG_NOTICE, - "nd6_prelist_add failed for %s/%d on %s " - "errno=%d, returnpr=%p\n", - IN6_PRINT(ip6buf, &newprc->ndprc_prefix.sin6_addr), - newprc->ndprc_plen, if_name(newprc->ndprc_ifp), - error, newpr); - goto end; /* we should just give up in this case. */ - } - - /* - * XXX: from the ND point of view, we can ignore a prefix - * with the on-link bit being zero. However, we need a - * prefix structure for references from autoconfigured - * addresses. Thus, we explicitly make sure that the prefix - * itself expires now. - */ - if (newpr->ndpr_raf_onlink == 0) { - newpr->ndpr_vltime = 0; - newpr->ndpr_pltime = 0; - in6_init_prefix_ltimes(newpr); - } - - pr = newpr; - } - - /* - * Address autoconfiguration based on Section 5.5.3 of RFC 2462. - * Note that pr must be non NULL at this point. - */ - - /* 5.5.3 (a). Ignore the prefix without the A bit set. */ - if (!newprc->ndprc_raf_auto) - goto end; - - /* - * 5.5.3 (b). the link-local prefix should have been ignored in - * nd6_ra_input. - */ - - /* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime. */ - if (newprc->ndprc_pltime > newprc->ndprc_vltime) { - error = EINVAL; /* XXX: won't be used */ - goto end; - } - - /* - * 5.5.3 (d). If the prefix advertised is not equal to the prefix of - * an address configured by stateless autoconfiguration already in the - * list of addresses associated with the interface, and the Valid - * Lifetime is not 0, form an address. We first check if we have - * a matching prefix. - * Note: we apply a clarification in rfc2462bis-02 here. We only - * consider autoconfigured addresses while RFC2462 simply said - * "address". - */ - ss = pserialize_read_enter(); - IFADDR_READER_FOREACH(ifa, ifp) { - struct in6_ifaddr *ia6; - u_int32_t remaininglifetime; - - if (ifa->ifa_addr->sa_family != AF_INET6) - continue; - - ia6 = (struct in6_ifaddr *)ifa; - - /* - * We only consider autoconfigured addresses as per rfc2462bis. - */ - if (!(ia6->ia6_flags & IN6_IFF_AUTOCONF)) - continue; - - /* - * Spec is not clear here, but I believe we should concentrate - * on unicast (i.e. not anycast) addresses. - * XXX: other ia6_flags? detached or duplicated? - */ - if ((ia6->ia6_flags & IN6_IFF_ANYCAST) != 0) - continue; - - /* - * Ignore the address if it is not associated with a prefix - * or is associated with a prefix that is different from this - * one. (pr is never NULL here) - */ - if (ia6->ia6_ndpr != pr) - continue; - - if (ia6_match == NULL) /* remember the first one */ - ia6_match = ia6; - - /* - * An already autoconfigured address matched. Now that we - * are sure there is at least one matched address, we can - * proceed to 5.5.3. (e): update the lifetimes according to the - * "two hours" rule and the privacy extension. - * We apply some clarifications in rfc2462bis: - * - use remaininglifetime instead of storedlifetime as a - * variable name - * - remove the dead code in the "two-hour" rule - */ -#define TWOHOUR (120*60) - lt6_tmp = ia6->ia6_lifetime; - if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME) - remaininglifetime = ND6_INFINITE_LIFETIME; - else if (time_uptime - ia6->ia6_updatetime > - lt6_tmp.ia6t_vltime) { - /* - * The case of "invalid" address. We should usually - * not see this case. - */ - remaininglifetime = 0; - } else - remaininglifetime = lt6_tmp.ia6t_vltime - - (time_uptime - ia6->ia6_updatetime); - - /* when not updating, keep the current stored lifetime. */ - lt6_tmp.ia6t_vltime = remaininglifetime; - - if (TWOHOUR < newprc->ndprc_vltime || - remaininglifetime < newprc->ndprc_vltime) { - lt6_tmp.ia6t_vltime = newprc->ndprc_vltime; - } else if (remaininglifetime <= TWOHOUR) { - if (auth) - lt6_tmp.ia6t_vltime = newprc->ndprc_vltime; - } else { - /* - * newprc->ndprc_vltime <= TWOHOUR && - * TWOHOUR < remaininglifetime - */ - lt6_tmp.ia6t_vltime = TWOHOUR; - } - - /* The 2 hour rule is not imposed for preferred lifetime. */ - lt6_tmp.ia6t_pltime = newprc->ndprc_pltime; - - in6_init_address_ltimes(pr, <6_tmp); - - /* - * We need to treat lifetimes for temporary addresses - * differently, according to - * draft-ietf-ipv6-privacy-addrs-v2-01.txt 3.3 (1); - * we only update the lifetimes when they are in the maximum - * intervals. - */ - if ((ia6->ia6_flags & IN6_IFF_TEMPORARY) != 0) { - u_int32_t maxvltime, maxpltime; - - if (ip6_temp_valid_lifetime > - (u_int32_t)((time_uptime - ia6->ia6_createtime) + - ip6_desync_factor)) { - maxvltime = ip6_temp_valid_lifetime - - (time_uptime - ia6->ia6_createtime) - - ip6_desync_factor; - } else - maxvltime = 0; - if (ip6_temp_preferred_lifetime > - (u_int32_t)((time_uptime - ia6->ia6_createtime) + - ip6_desync_factor)) { - maxpltime = ip6_temp_preferred_lifetime - - (time_uptime - ia6->ia6_createtime) - - ip6_desync_factor; - } else - maxpltime = 0; - - if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME || - lt6_tmp.ia6t_vltime > maxvltime) { - lt6_tmp.ia6t_vltime = maxvltime; - } - if (lt6_tmp.ia6t_pltime == ND6_INFINITE_LIFETIME || - lt6_tmp.ia6t_pltime > maxpltime) { - lt6_tmp.ia6t_pltime = maxpltime; - } - } - - ia6->ia6_lifetime = lt6_tmp; - ia6->ia6_updatetime = time_uptime; - } - pserialize_read_exit(ss); - - if (ia6_match == NULL && newprc->ndprc_vltime) { - int ifidlen; - struct in6_ifaddr *ia6; - struct psref psref; - - /* - * 5.5.3 (d) (continued) - * No address matched and the valid lifetime is non-zero. - * Create a new address. - */ - - /* - * Prefix Length check: - * If the sum of the prefix length and interface identifier - * length does not equal 128 bits, the Prefix Information - * option MUST be ignored. The length of the interface - * identifier is defined in a separate link-type specific - * document. - */ - ifidlen = in6_if2idlen(ifp); - if (ifidlen < 0) { - /* this should not happen, so we always log it. */ - log(LOG_ERR, "%s: IFID undefined (%s)\n", - __func__, if_name(ifp)); - goto end; - } - if (ifidlen + pr->ndpr_plen != 128) { - nd6log(LOG_INFO, - "invalid prefixlen %d for %s, ignored\n", - pr->ndpr_plen, if_name(ifp)); - goto end; - } - - if ((ia6 = in6_ifadd(newprc, mcast, &psref)) != NULL) { - /* - * note that we should use pr (not newprc) for reference. - */ - pr->ndpr_refcnt++; - ia6->ia6_ndpr = pr; - - /* toggle onlink state if the address was assigned - * a prefix route. */ - if (ia6->ia_flags & IFA_ROUTE) - pr->ndpr_stateflags |= NDPRF_ONLINK; - - /* - * draft-ietf-ipngwg-temp-addresses-v2-00 3.3 (2). - * When a new public address is created as described - * in RFC2462, also create a new temporary address. - * - * draft-ietf-ipngwg-temp-addresses-v2-00 3.5. - * When an interface connects to a new link, a new - * randomized interface identifier should be generated - * immediately together with a new set of temporary - * addresses. Thus, we specifiy 1 as the 2nd arg of - * in6_tmpifadd(). - */ - if (ip6_use_tempaddr) { - int e; - if ((e = in6_tmpifadd(ia6, 1, 1)) != 0) { - nd6log(LOG_NOTICE, - "failed to create a temporary " - "address, errno=%d\n", e); - } - } - ia6_release(ia6, &psref); - - /* - * A newly added address might affect the status - * of other addresses, so we check and update it. - * XXX: what if address duplication happens? - */ - nd6_pfxlist_onlink_check(); - } else { - /* just set an error. do not bark here. */ - error = EADDRNOTAVAIL; /* XXX: might be unused. */ - } - } - - end: - return error; -} - -/* - * A supplement function used in the on-link detection below; - * detect if a given prefix has a (probably) reachable advertising router. - * XXX: lengthy function name... - */ -static struct nd_pfxrouter * -find_pfxlist_reachable_router(struct nd_prefix *pr) -{ - struct nd_pfxrouter *pfxrtr; - - for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr; - pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) { - if (pfxrtr->router->ifp->if_flags & IFF_UP && - pfxrtr->router->ifp->if_link_state != LINK_STATE_DOWN && - nd6_is_llinfo_probreach(pfxrtr->router)) - break; /* found */ - } - - return (pfxrtr); -} - -/* - * Check if each prefix in the prefix list has at least one available router - * that advertised the prefix (a router is "available" if its neighbor cache - * entry is reachable or probably reachable). - * If the check fails, the prefix may be off-link, because, for example, - * we have moved from the network but the lifetime of the prefix has not - * expired yet. So we should not use the prefix if there is another prefix - * that has an available router. - * But, if there is no prefix that has an available router, we still regards - * all the prefixes as on-link. This is because we can't tell if all the - * routers are simply dead or if we really moved from the network and there - * is no router around us. - */ -void -nd6_pfxlist_onlink_check(void) -{ - struct nd_prefix *pr; - struct in6_ifaddr *ia; - struct nd_defrouter *dr; - struct nd_pfxrouter *pfxrtr = NULL; - int s; - char ip6buf[INET6_ADDRSTRLEN]; - - ND6_ASSERT_WLOCK(); - - /* - * Check if there is a prefix that has a reachable advertising - * router. - */ - ND_PREFIX_LIST_FOREACH(pr) { - if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr)) - break; - } - /* - * If we have no such prefix, check whether we still have a router - * that does not advertise any prefixes. - */ - if (pr == NULL) { - ND_DEFROUTER_LIST_FOREACH(dr) { - struct nd_prefix *pr0; - - ND_PREFIX_LIST_FOREACH(pr0) { - if ((pfxrtr = pfxrtr_lookup(pr0, dr)) != NULL) - break; - } - if (pfxrtr) - break; - } - } - if (pr != NULL || (!ND_DEFROUTER_LIST_EMPTY() && !pfxrtr)) { - /* - * There is at least one prefix that has a reachable router, - * or at least a router which probably does not advertise - * any prefixes. The latter would be the case when we move - * to a new link where we have a router that does not provide - * prefixes and we configure an address by hand. - * Detach prefixes which have no reachable advertising - * router, and attach other prefixes. - */ - ND_PREFIX_LIST_FOREACH(pr) { - /* XXX: a link-local prefix should never be detached */ - if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) - continue; - - /* - * we aren't interested in prefixes without the L bit - * set. - */ - if (pr->ndpr_raf_onlink == 0) - continue; - - if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && - find_pfxlist_reachable_router(pr) == NULL) - pr->ndpr_stateflags |= NDPRF_DETACHED; - if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && - find_pfxlist_reachable_router(pr) != 0) - pr->ndpr_stateflags &= ~NDPRF_DETACHED; - } - } else { - /* there is no prefix that has a reachable router */ - ND_PREFIX_LIST_FOREACH(pr) { - if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) - continue; - - if (pr->ndpr_raf_onlink == 0) - continue; - - if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0) - pr->ndpr_stateflags &= ~NDPRF_DETACHED; - } - } - - /* - * Remove each interface route associated with a (just) detached - * prefix, and reinstall the interface route for a (just) attached - * prefix. Note that all attempt of reinstallation does not - * necessarily success, when a same prefix is shared among multiple - * interfaces. Such cases will be handled in nd6_prefix_onlink, - * so we don't have to care about them. - */ - ND_PREFIX_LIST_FOREACH(pr) { - int e; - - if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr)) - continue; - - if (pr->ndpr_raf_onlink == 0) - continue; - - if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 && - (pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { - if ((e = nd6_prefix_offlink(pr)) != 0) { - nd6log(LOG_ERR, - "failed to make %s/%d offlink, errno=%d\n", - IN6_PRINT(ip6buf, - &pr->ndpr_prefix.sin6_addr), - pr->ndpr_plen, e); - } - } - if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && - (pr->ndpr_stateflags & NDPRF_ONLINK) == 0 && - pr->ndpr_raf_onlink) { - if ((e = nd6_prefix_onlink(pr)) != 0) { - nd6log(LOG_ERR, - "failed to make %s/%d onlink, errno=%d\n", - IN6_PRINT(ip6buf, - &pr->ndpr_prefix.sin6_addr), - pr->ndpr_plen, e); - } - } - } - - int bound = curlwp_bind(); - /* - * Changes on the prefix status might affect address status as well. - * Make sure that all addresses derived from an attached prefix are - * attached, and that all addresses derived from a detached prefix are - * detached. Note, however, that a manually configured address should - * always be attached. - * The precise detection logic is same as the one for prefixes. - */ - s = pserialize_read_enter(); - IN6_ADDRLIST_READER_FOREACH(ia) { - struct psref psref; - bool found; - - if (!(ia->ia6_flags & IN6_IFF_AUTOCONF)) - continue; - - if (ia->ia6_ndpr == NULL) { - /* - * This can happen when we first configure the address - * (i.e. the address exists, but the prefix does not). - * XXX: complicated relationships... - */ - continue; - } - - ia6_acquire(ia, &psref); - pserialize_read_exit(s); - - found = find_pfxlist_reachable_router(ia->ia6_ndpr) != NULL; - - s = pserialize_read_enter(); - ia6_release(ia, &psref); - if (found) - break; - } - pserialize_read_exit(s); - - if (ia) { - s = pserialize_read_enter(); - IN6_ADDRLIST_READER_FOREACH(ia) { - struct ifaddr *ifa = (struct ifaddr *)ia; - struct psref psref; - - if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) - continue; - - if (ia->ia6_ndpr == NULL) /* XXX: see above. */ - continue; - - ia6_acquire(ia, &psref); - pserialize_read_exit(s); - - if (find_pfxlist_reachable_router(ia->ia6_ndpr)) { - if (ia->ia6_flags & IN6_IFF_DETACHED) { - ia->ia6_flags &= ~IN6_IFF_DETACHED; - ia->ia6_flags |= IN6_IFF_TENTATIVE; - nd6_dad_start(ifa, - 0); - /* We will notify the routing socket - * of the DAD result, so no need to - * here */ - } - } else { - if ((ia->ia6_flags & IN6_IFF_DETACHED) == 0) { - ia->ia6_flags |= IN6_IFF_DETACHED; - rt_addrmsg(RTM_NEWADDR, ifa); - } - } - - s = pserialize_read_enter(); - ia6_release(ia, &psref); - } - pserialize_read_exit(s); - } - else { - s = pserialize_read_enter(); - IN6_ADDRLIST_READER_FOREACH(ia) { - if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0) - continue; - - if (ia->ia6_flags & IN6_IFF_DETACHED) { - struct ifaddr *ifa = (struct ifaddr *)ia; - struct psref psref; - - ia->ia6_flags &= ~IN6_IFF_DETACHED; - ia->ia6_flags |= IN6_IFF_TENTATIVE; - - ia6_acquire(ia, &psref); - pserialize_read_exit(s); - - /* Do we need a delay in this case? */ - nd6_dad_start(ifa, 0); - - s = pserialize_read_enter(); - ia6_release(ia, &psref); - } - } - pserialize_read_exit(s); - } - - curlwp_bindx(bound); -} - -static int -nd6_prefix_onlink(struct nd_prefix *pr) -{ - struct ifaddr *ifa; - struct ifnet *ifp = pr->ndpr_ifp; - struct sockaddr_in6 mask6; - struct nd_prefix *opr; - u_long rtflags; - int error = 0; - struct psref psref; - int bound; - char ip6buf[INET6_ADDRSTRLEN]; - char ip6bufp[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN]; - - ND6_ASSERT_WLOCK(); - - /* sanity check */ - if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) { - nd6log(LOG_ERR, "%s/%d is already on-link\n", - IN6_PRINT(ip6buf, &pr->ndpr_prefix.sin6_addr), - pr->ndpr_plen); - return (EEXIST); - } - - /* - * Add the interface route associated with the prefix. Before - * installing the route, check if there's the same prefix on another - * interface, and the prefix has already installed the interface route. - * Although such a configuration is expected to be rare, we explicitly - * allow it. - */ - ND_PREFIX_LIST_FOREACH(opr) { - if (opr == pr) - continue; - - if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0) - continue; - - if (opr->ndpr_plen == pr->ndpr_plen && - in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, - &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) - return (0); - } - - /* - * We prefer link-local addresses as the associated interface address. - */ - /* search for a link-local addr */ - bound = curlwp_bind(); - ifa = (struct ifaddr *)in6ifa_ifpforlinklocal_psref(ifp, - IN6_IFF_NOTREADY | IN6_IFF_ANYCAST, &psref); - if (ifa == NULL) { - int s = pserialize_read_enter(); - IFADDR_READER_FOREACH(ifa, ifp) { - if (ifa->ifa_addr->sa_family == AF_INET6) - break; - } - if (ifa != NULL) - ifa_acquire(ifa, &psref); - pserialize_read_exit(s); - /* should we care about ia6_flags? */ - } - if (ifa == NULL) { - /* - * This can still happen, when, for example, we receive an RA - * containing a prefix with the L bit set and the A bit clear, - * after removing all IPv6 addresses on the receiving - * interface. This should, of course, be rare though. - */ - nd6log(LOG_NOTICE, "failed to find any ifaddr" - " to add route for a prefix(%s/%d) on %s\n", - IN6_PRINT(ip6buf, &pr->ndpr_prefix.sin6_addr), - pr->ndpr_plen, if_name(ifp)); - curlwp_bindx(bound); - return (0); - } - - /* - * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs. - * ifa->ifa_rtrequest = nd6_rtrequest; - */ - memset(&mask6, 0, sizeof(mask6)); - mask6.sin6_family = AF_INET6; - mask6.sin6_len = sizeof(mask6); - mask6.sin6_addr = pr->ndpr_mask; - /* rtrequest() will probably set RTF_UP, but we're not sure. */ - rtflags = ifa->ifa_flags | RTF_UP; - if (nd6_need_cache(ifp)) { - /* explicitly set in case ifa_flags does not set the flag. */ - rtflags |= RTF_CONNECTED; - } else { - /* - * explicitly clear the cloning bit in case ifa_flags sets it. - */ - rtflags &= ~RTF_CONNECTED; - } - error = rtrequest_newmsg(RTM_ADD, sin6tosa(&pr->ndpr_prefix), - ifa->ifa_addr, sin6tosa(&mask6), rtflags); - if (error == 0) { - nd6_numroutes++; - pr->ndpr_stateflags |= NDPRF_ONLINK; - } else { - nd6log(LOG_ERR, "failed to add route for a" - " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx " - "errno = %d\n", - IN6_PRINT(ip6bufp, &pr->ndpr_prefix.sin6_addr), - pr->ndpr_plen, if_name(ifp), - IN6_PRINT(ip6buf, - &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr), - IN6_PRINT(ip6bufm, &mask6.sin6_addr), rtflags, error); - } - ifa_release(ifa, &psref); - curlwp_bindx(bound); - - return (error); -} - -static int -nd6_prefix_offlink(struct nd_prefix *pr) -{ - int error = 0; - struct ifnet *ifp = pr->ndpr_ifp; - struct nd_prefix *opr; - struct sockaddr_in6 sa6, mask6; - char ip6buf[INET6_ADDRSTRLEN]; - - ND6_ASSERT_WLOCK(); - - /* sanity check */ - if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) { - nd6log(LOG_ERR, "%s/%d is already off-link\n", - IN6_PRINT(ip6buf, &pr->ndpr_prefix.sin6_addr), - pr->ndpr_plen); - return (EEXIST); - } - - sockaddr_in6_init(&sa6, &pr->ndpr_prefix.sin6_addr, 0, 0, 0); - sockaddr_in6_init(&mask6, &pr->ndpr_mask, 0, 0, 0); - error = rtrequest_newmsg(RTM_DELETE, sin6tosa(&sa6), NULL, - sin6tosa(&mask6), 0); - if (error == 0) { - pr->ndpr_stateflags &= ~NDPRF_ONLINK; - nd6_numroutes--; - - /* - * There might be the same prefix on another interface, - * the prefix which could not be on-link just because we have - * the interface route (see comments in nd6_prefix_onlink). - * If there's one, try to make the prefix on-link on the - * interface. - */ - ND_PREFIX_LIST_FOREACH(opr) { - if (opr == pr) - continue; - - if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0) - continue; - - /* - * KAME specific: detached prefixes should not be - * on-link. - */ - if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0) - continue; - - if (opr->ndpr_plen == pr->ndpr_plen && - in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, - &opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) { - int e; - - if ((e = nd6_prefix_onlink(opr)) != 0) { - nd6log(LOG_ERR, "failed to " - "recover a prefix %s/%d from %s " - "to %s (errno = %d)\n", - IN6_PRINT(ip6buf, - &opr->ndpr_prefix.sin6_addr), - opr->ndpr_plen, if_name(ifp), - if_name(opr->ndpr_ifp), e); - } - } - } - } else { - /* XXX: can we still set the NDPRF_ONLINK flag? */ - nd6log(LOG_ERR, "failed to delete route: " - "%s/%d on %s (errno = %d)\n", - IN6_PRINT(ip6buf, &sa6.sin6_addr), pr->ndpr_plen, - if_name(ifp), - error); - } - - return error; -} - -static struct in6_ifaddr * -in6_ifadd(struct nd_prefixctl *prc, int mcast, struct psref *psref) -{ - struct ifnet *ifp = prc->ndprc_ifp; - struct ifaddr *ifa; - struct in6_aliasreq ifra; - struct in6_ifaddr *ia, *ib; - int error, plen0; - struct in6_addr mask; - int prefixlen = prc->ndprc_plen; - int updateflags; - int s; - char ip6buf[INET6_ADDRSTRLEN]; - - ND6_ASSERT_WLOCK(); - - in6_prefixlen2mask(&mask, prefixlen); - - /* - * find a link-local address (will be interface ID). - * Is it really mandatory? Theoretically, a global or a site-local - * address can be configured without a link-local address, if we - * have a unique interface identifier... - * - * it is not mandatory to have a link-local address, we can generate - * interface identifier on the fly. we do this because: - * (1) it should be the easiest way to find interface identifier. - * (2) RFC2462 5.4 suggesting the use of the same interface identifier - * for multiple addresses on a single interface, and possible shortcut - * of DAD. we omitted DAD for this reason in the past. - * (3) a user can prevent autoconfiguration of global address - * by removing link-local address by hand (this is partly because we - * don't have other way to control the use of IPv6 on an interface. - * this has been our design choice - cf. NRL's "ifconfig auto"). - * (4) it is easier to manage when an interface has addresses - * with the same interface identifier, than to have multiple addresses - * with different interface identifiers. - */ - s = pserialize_read_enter(); - ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */ - if (ifa) - ib = (struct in6_ifaddr *)ifa; - else { - pserialize_read_exit(s); - return NULL; - } - -#if 0 /* don't care link local addr state, and always do DAD */ - /* if link-local address is not eligible, do not autoconfigure. */ - if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) { - printf("in6_ifadd: link-local address not ready\n"); - return NULL; - } -#endif - - /* prefixlen + ifidlen must be equal to 128 */ - plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL); - if (prefixlen != plen0) { - nd6log(LOG_INFO, "wrong prefixlen for %s " - "(prefix=%d ifid=%d)\n", - if_name(ifp), prefixlen, 128 - plen0); - pserialize_read_exit(s); - return NULL; - } - - /* make ifaddr */ - - memset(&ifra, 0, sizeof(ifra)); - /* - * in6_update_ifa() does not use ifra_name, but we accurately set it - * for safety. - */ - strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); - sockaddr_in6_init(&ifra.ifra_addr, &prc->ndprc_prefix.sin6_addr, 0, 0, 0); - /* prefix */ - ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0]; - ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1]; - ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2]; - ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3]; - - /* interface ID */ - ifra.ifra_addr.sin6_addr.s6_addr32[0] |= - (ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]); - ifra.ifra_addr.sin6_addr.s6_addr32[1] |= - (ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]); - ifra.ifra_addr.sin6_addr.s6_addr32[2] |= - (ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]); - ifra.ifra_addr.sin6_addr.s6_addr32[3] |= - (ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]); - pserialize_read_exit(s); - - /* new prefix mask. */ - sockaddr_in6_init(&ifra.ifra_prefixmask, &mask, 0, 0, 0); - - /* lifetimes */ - ifra.ifra_lifetime.ia6t_vltime = prc->ndprc_vltime; - ifra.ifra_lifetime.ia6t_pltime = prc->ndprc_pltime; - - /* XXX: scope zone ID? */ - - ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */ - - /* - * Make sure that we do not have this address already. This should - * usually not happen, but we can still see this case, e.g., if we - * have manually configured the exact address to be configured. - */ - s = pserialize_read_enter(); - if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) { - /* this should be rare enough to make an explicit log */ - log(LOG_INFO, "in6_ifadd: %s is already configured\n", - IN6_PRINT(ip6buf, &ifra.ifra_addr.sin6_addr)); - pserialize_read_exit(s); - return (NULL); - } - pserialize_read_exit(s); - - /* - * Allocate ifaddr structure, link into chain, etc. - * If we are going to create a new address upon receiving a multicasted - * RA, we need to impose a random delay before starting DAD. - * [draft-ietf-ipv6-rfc2462bis-02.txt, Section 5.4.2] - */ - updateflags = 0; - if (mcast) - updateflags |= IN6_IFAUPDATE_DADDELAY; - if ((error = in6_update_ifa(ifp, &ifra, updateflags)) != 0) { - nd6log(LOG_ERR, "failed to make ifaddr %s on %s (errno=%d)\n", - IN6_PRINT(ip6buf, &ifra.ifra_addr.sin6_addr), if_name(ifp), - error); - return (NULL); /* ifaddr must not have been allocated. */ - } - - ia = in6ifa_ifpwithaddr_psref(ifp, &ifra.ifra_addr.sin6_addr, psref); - - return (ia); /* this is always non-NULL */ -} - -int -in6_tmpifadd( - const struct in6_ifaddr *ia0, /* corresponding public address */ - int forcegen, - int dad_delay) -{ - struct ifnet *ifp = ia0->ia_ifa.ifa_ifp; - struct in6_ifaddr *newia, *ia; - struct in6_aliasreq ifra; - int i, error; - int trylimit = 3; /* XXX: adhoc value */ - int updateflags; - u_int32_t randid[2]; - u_int32_t vltime0, pltime0; - int s; - - ND6_ASSERT_WLOCK(); - - memset(&ifra, 0, sizeof(ifra)); - strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); - ifra.ifra_addr = ia0->ia_addr; - /* copy prefix mask */ - ifra.ifra_prefixmask = ia0->ia_prefixmask; - /* clear the old IFID */ - for (i = 0; i < 4; i++) { - ifra.ifra_addr.sin6_addr.s6_addr32[i] &= - ifra.ifra_prefixmask.sin6_addr.s6_addr32[i]; - } - - again: - if (in6_get_tmpifid(ifp, (u_int8_t *)randid, - (const u_int8_t *)&ia0->ia_addr.sin6_addr.s6_addr[8], forcegen)) { - nd6log(LOG_NOTICE, "failed to find a good random IFID\n"); - return (EINVAL); - } - ifra.ifra_addr.sin6_addr.s6_addr32[2] |= - (randid[0] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[2])); - ifra.ifra_addr.sin6_addr.s6_addr32[3] |= - (randid[1] & ~(ifra.ifra_prefixmask.sin6_addr.s6_addr32[3])); - - /* - * in6_get_tmpifid() quite likely provided a unique interface ID. - * However, we may still have a chance to see collision, because - * there may be a time lag between generation of the ID and generation - * of the address. So, we'll do one more sanity check. - */ - s = pserialize_read_enter(); - IN6_ADDRLIST_READER_FOREACH(ia) { - if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, - &ifra.ifra_addr.sin6_addr)) { - pserialize_read_exit(s); - if (trylimit-- == 0) { - /* - * Give up. Something strange should have - * happened. - */ - nd6log(LOG_NOTICE, - "failed to find a unique random IFID\n"); - return (EEXIST); - } - forcegen = 1; - goto again; - } - } - pserialize_read_exit(s); - - /* - * The Valid Lifetime is the lower of the Valid Lifetime of the - * public address or TEMP_VALID_LIFETIME. - * The Preferred Lifetime is the lower of the Preferred Lifetime - * of the public address or TEMP_PREFERRED_LIFETIME - - * DESYNC_FACTOR. - */ - if (ia0->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { - vltime0 = IFA6_IS_INVALID(ia0) ? 0 : - (ia0->ia6_lifetime.ia6t_vltime - - (time_uptime - ia0->ia6_updatetime)); - if (vltime0 > ip6_temp_valid_lifetime) - vltime0 = ip6_temp_valid_lifetime; - } else - vltime0 = ip6_temp_valid_lifetime; - if (ia0->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { - pltime0 = IFA6_IS_DEPRECATED(ia0) ? 0 : - (ia0->ia6_lifetime.ia6t_pltime - - (time_uptime - ia0->ia6_updatetime)); - if (pltime0 > ip6_temp_preferred_lifetime - ip6_desync_factor){ - pltime0 = ip6_temp_preferred_lifetime - - ip6_desync_factor; - } - } else - pltime0 = ip6_temp_preferred_lifetime - ip6_desync_factor; - ifra.ifra_lifetime.ia6t_vltime = vltime0; - ifra.ifra_lifetime.ia6t_pltime = pltime0; - - /* - * A temporary address is created only if this calculated Preferred - * Lifetime is greater than REGEN_ADVANCE time units. - */ - if (ifra.ifra_lifetime.ia6t_pltime <= ip6_temp_regen_advance) - return (0); - - /* XXX: scope zone ID? */ - - ifra.ifra_flags |= (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY); - - /* allocate ifaddr structure, link into chain, etc. */ - updateflags = 0; - if (dad_delay) - updateflags |= IN6_IFAUPDATE_DADDELAY; - if ((error = in6_update_ifa(ifp, &ifra, updateflags)) != 0) - return (error); - - s = pserialize_read_enter(); - newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr); - if (newia == NULL) { /* XXX: can it happen? */ - pserialize_read_exit(s); - nd6log(LOG_ERR, - "ifa update succeeded, but we got no ifaddr\n"); - return (EINVAL); /* XXX */ - } - newia->ia6_ndpr = ia0->ia6_ndpr; - newia->ia6_ndpr->ndpr_refcnt++; - pserialize_read_exit(s); - - /* - * A newly added address might affect the status of other addresses. - * XXX: when the temporary address is generated with a new public - * address, the onlink check is redundant. However, it would be safe - * to do the check explicitly everywhere a new address is generated, - * and, in fact, we surely need the check when we create a new - * temporary address due to deprecation of an old temporary address. - */ - nd6_pfxlist_onlink_check(); - - return (0); -} - -static int -in6_init_prefix_ltimes(struct nd_prefix *ndpr) -{ - - ND6_ASSERT_WLOCK(); - - /* check if preferred lifetime > valid lifetime. RFC2462 5.5.3 (c) */ - if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) { - nd6log(LOG_INFO, "preferred lifetime" - "(%d) is greater than valid lifetime(%d)\n", - (u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime); - return (EINVAL); - } - if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME) - ndpr->ndpr_preferred = 0; - else - ndpr->ndpr_preferred = time_uptime + ndpr->ndpr_pltime; - if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME) - ndpr->ndpr_expire = 0; - else - ndpr->ndpr_expire = time_uptime + ndpr->ndpr_vltime; - - return 0; -} - -static void -in6_init_address_ltimes(struct nd_prefix *newpr, - struct in6_addrlifetime *lt6) -{ - - /* Valid lifetime must not be updated unless explicitly specified. */ - /* init ia6t_expire */ - if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME) - lt6->ia6t_expire = 0; - else { - lt6->ia6t_expire = time_uptime; - lt6->ia6t_expire += lt6->ia6t_vltime; - } - - /* init ia6t_preferred */ - if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME) - lt6->ia6t_preferred = 0; - else { - lt6->ia6t_preferred = time_uptime; - lt6->ia6t_preferred += lt6->ia6t_pltime; - } -} - -/* - * Delete all the routing table entries that use the specified gateway. - * XXX: this function causes search through all entries of routing table, so - * it shouldn't be called when acting as a router. - */ -void -nd6_rt_flush(struct in6_addr *gateway, struct ifnet *ifp) -{ -#ifndef NET_MPSAFE - int s = splsoftnet(); -#endif - - /* We'll care only link-local addresses */ - if (!IN6_IS_ADDR_LINKLOCAL(gateway)) - goto out; - - rt_delete_matched_entries(AF_INET6, rt6_deleteroute_matcher, gateway); - -out: -#ifndef NET_MPSAFE - splx(s); -#endif - return; /* XXX gcc */ -} - -static int -rt6_deleteroute_matcher(struct rtentry *rt, void *arg) -{ - struct in6_addr *gate = (struct in6_addr *)arg; - - if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) - return (0); - - if (!IN6_ARE_ADDR_EQUAL(gate, &satosin6(rt->rt_gateway)->sin6_addr)) - return (0); - - /* - * Do not delete a static route. - * XXX: this seems to be a bit ad-hoc. Should we consider the - * 'cloned' bit instead? - */ - if ((rt->rt_flags & RTF_STATIC) != 0) - return (0); - - /* - * We delete only host route. This means, in particular, we don't - * delete default route. - */ - if ((rt->rt_flags & RTF_HOST) == 0) - return (0); - - return 1; -} diff -r 80f27e12612b tests/net/ndp/Makefile --- a/tests/net/ndp/Makefile Tue Apr 21 12:23:13 2020 +0000 +++ b/tests/net/ndp/Makefile Wed Apr 22 00:54:02 2020 +0100 @@ -5,7 +5,7 @@ TESTSDIR= ${TESTSBASE}/net/ndp -.for name in dad ndp ra +.for name in dad ndp TESTS_SH+= t_${name} TESTS_SH_SRC_t_${name}= ../net_common.sh t_${name}.sh .endfor diff -r 80f27e12612b tests/net/ndp/t_ra.sh --- a/tests/net/ndp/t_ra.sh Tue Apr 21 12:23:13 2020 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,866 +0,0 @@ -# $NetBSD: t_ra.sh,v 1.33 2019/10/16 07:42:22 ozaki-r Exp $ -# -# Copyright (c) 2015 Internet Initiative Japan Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS -# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS -# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# - -RUMPSRV=unix://r1 -RUMPSRV1_2=unix://r12 -RUMPCLI=unix://r2 -RUMPSRV3=unix://r3 -RUMPSRV4=unix://r4 -IP6SRV=fc00:1::1 -IP6SRV1_2=fc00:1::2 -IP6SRV_PREFIX=fc00:1: -IP6CLI=fc00:2::2 -IP6SRV3=fc00:3::1 -IP6SRV3_PREFIX=fc00:3: -IP6SRV4=fc00:4::1 -IP6SRV4_PREFIX=fc00:4: -PIDFILE=./rump.rtadvd.pid -PIDFILE1_2=./rump.rtadvd.pid12 -PIDFILE3=./rump.rtadvd.pid3 -PIDFILE4=./rump.rtadvd.pid4 -CONFIG=./rtadvd.conf -DEBUG=${DEBUG:-false} - -RUMP_PROGS="rump_server rump.rtadvd rump.ndp rump.ifconfig rump.netstat" - -init_server() -{ - - export RUMP_SERVER=$1 - atf_check -s exit:0 -o match:'0.->.1' \ - rump.sysctl -w net.inet6.ip6.forwarding=1 - export LD_PRELOAD=/usr/lib/librumphijack.so - atf_check -s exit:0 mkdir -p /rump/var/chroot/rtadvd - unset LD_PRELOAD - unset RUMP_SERVER -} - -setup_shmif0() -{ - local sock=$1 - local IP6ADDR=$2 - - rump_server_add_iface $sock shmif0 bus1 - - export RUMP_SERVER=$sock - atf_check -s exit:0 rump.ifconfig shmif0 inet6 ${IP6ADDR} - atf_check -s exit:0 rump.ifconfig shmif0 up - atf_check -s exit:0 rump.ifconfig -w 10 - - $DEBUG && rump.ifconfig -} - -kill_rtadvd() -{ - local pid=$(cat "$1") - - test -n "$pid" && { - case "$pid" in - *[!0-9]*) return 1;; - esac - test "$pid" -gt 1 && kill -s KILL "${pid}" - } - rm -f "$1" -} - -terminate_rtadvd() -{ - local pidfile=$1 - local n=5 - - if ! [ -f "$pidfile" ]; then - return - fi - - local pid=$(cat "$pidfile") - - test -n "${pid}" && kill -s TERM "${pid}" - - # Note, rtadvd cannot remove its own pidfile, it chroots after - # creating it (and if it chroot'd first, we would not be able to - # control where it puts the thing, and so it would be useless.) - # However, it does truncate it... so watch for that. - while [ -s "$pidfile" ]; do - n=$((n - 1)) - if [ "$n" = 0 ]; then - kill_rtadvd "$pidfile" - return - fi - sleep 0.2 - done - # and finally complete the cleanup that rtadvd did not do. - rm -f "$pidfile" -} - -create_rtadvdconfig() -{ - cat << _EOF > ${CONFIG} -shmif0:\\ - :mtu#1300:maxinterval#4:mininterval#3: -_EOF -} - -create_rtadvdconfig_rltime() -{ - cat << _EOF > ${CONFIG} -shmif0:\\ - :mtu#1300:maxinterval#4:mininterval#3:rltime#$1: -_EOF - $DEBUG && cat ${CONFIG} -} - -create_rtadvdconfig_vltime() -{ - cat << _EOF > ${CONFIG} -shmif0:\\ - :mtu#1300:maxinterval#4:mininterval#3:addr="$1":vltime#$2: -_EOF - $DEBUG && cat ${CONFIG} -} - -RA_count() -{ - RUMP_SERVER="$1" rump.netstat -p icmp6 | sed -n ' - $ { - s/^.*$/0/p - q - } - /router advertisement:/!d - s/.*router advertisement: *// - s/[ ]*$// - s/^$/0/ - p - q - ' -} - -await_RA() -{ - local N=$(RA_count "$1") - while [ "$(RA_count "$1")" -le "$N" ]; do - sleep 0.2 - done -} - -start_rtadvd() -{ - local RUMP_SERVER="$1" - export RUMP_SERVER - - atf_check -s exit:0 -e ignore \ - rump.rtadvd -D -c ${CONFIG} -p "$2" shmif0 - - # don't wait for the pid file to appear and get a pid in it. - # we look for receiving RAs instead, must more reliable - # extra delay here increases possibility of RA arriving before - # we start looking (which means we then wait for the next .. boring!) -} - -check_entries() -{ - local RUMP_SERVER="$1" - local srv=$2 - local addr_prefix=$3 - local mac_srv= ll_srv= - export RUMP_SERVER - - ll_srv=$(get_linklocal_addr "$srv" shmif0) - mac_srv=$(get_macaddr "$srv" shmif0) - - $DEBUG && dump_entries - atf_check -s exit:0 -o match:if=shmif0 rump.ndp -r - atf_check -s exit:0 -o match:advertised \ - -o match:"${ll_srv}%shmif0 \(reachable\)" \ - rump.ndp -p - atf_check -s exit:0 -o match:linkmtu=1300 rump.ndp -n -i shmif0 - atf_check -s exit:0 \ - -o match:"$ll_srv%shmif0 +$mac_srv +shmif0 +$ONEDAYISH S R" \ - -o not-match:"$addr_prefix" \ - rump.ndp -n -a - atf_check -s exit:0 \ - -o match:"$addr_prefix.+<(TENTATIVE,)?AUTOCONF>" \ - rump.ifconfig shmif0 inet6 -} - -dump_entries() -{ - local marker="+-+-+-+-+-+-+-+-+" - - printf '%s %s\n' "$marker" 'ndp -n -a' - rump.ndp -n -a - printf '%s %s\n' "$marker" 'ndp -p' - rump.ndp -p - printf '%s %s\n' "$marker" 'ndp -r' - rump.ndp -r - printf '%s\n' "$marker" -} - -atf_test_case ra_basic cleanup -ra_basic_head() -{ - - atf_set "descr" "Tests for basic functions of router advaertisement(RA)" - atf_set "require.progs" "${RUMP_PROGS}" -} - -ra_basic_body() -{ - - rump_server_fs_start $RUMPSRV netinet6 - rump_server_start $RUMPCLI netinet6 - - setup_shmif0 ${RUMPSRV} ${IP6SRV} - init_server $RUMPSRV - - setup_shmif0 ${RUMPCLI} ${IP6CLI} - export RUMP_SERVER=${RUMPCLI} - $DEBUG && rump.ndp -n -a - atf_check -s exit:0 -o match:'= 0' \ - rump.sysctl net.inet6.ip6.accept_rtadv - unset RUMP_SERVER - - create_rtadvdconfig - start_rtadvd $RUMPSRV $PIDFILE - await_RA "${RUMPCLI}" - - export RUMP_SERVER=${RUMPCLI} - atf_check -s exit:0 -o empty rump.ndp -r - atf_check -s exit:0 -o not-match:advertised rump.ndp -p - atf_check -s exit:0 -o match:linkmtu=0 rump.ndp -n -i shmif0 - atf_check -s exit:0 -o not-match:'S R' -o not-match:fc00:1: \ - rump.ndp -n -a - atf_check -s exit:0 -o not-match:fc00:1: rump.ifconfig shmif0 inet6 - unset RUMP_SERVER - - terminate_rtadvd $PIDFILE - - RUMP_SERVER=${RUMPCLI} atf_check -s exit:0 -o match:'0 -> 1' \ - rump.sysctl -w net.inet6.ip6.accept_rtadv=1 - - start_rtadvd $RUMPSRV $PIDFILE - await_RA "${RUMPCLI}" - - check_entries $RUMPCLI $RUMPSRV $IP6SRV_PREFIX - - terminate_rtadvd $PIDFILE - - rump_server_destroy_ifaces -} - -ra_basic_cleanup() -{ - - $DEBUG && dump - terminate_rtadvd $PIDFILE - cleanup -} - -atf_test_case ra_flush_prefix_entries cleanup -ra_flush_prefix_entries_head() -{ - - atf_set "descr" "Tests for flushing prefixes (ndp -P)" - atf_set "require.progs" "${RUMP_PROGS}" -} - -ra_flush_prefix_entries_body() -{ - - rump_server_fs_start $RUMPSRV netinet6 - rump_server_start $RUMPCLI netinet6 - - setup_shmif0 ${RUMPSRV} ${IP6SRV} - setup_shmif0 ${RUMPCLI} ${IP6CLI} - - init_server $RUMPSRV - - create_rtadvdconfig - - export RUMP_SERVER=${RUMPCLI} - atf_check -s exit:0 -o match:'0 -> 1' \ - rump.sysctl -w net.inet6.ip6.accept_rtadv=1 - unset RUMP_SERVER - - start_rtadvd $RUMPSRV $PIDFILE - await_RA "${RUMPCLI}" - - check_entries $RUMPCLI $RUMPSRV $IP6SRV_PREFIX - - export RUMP_SERVER=${RUMPCLI} - - # Terminate rtadvd to prevent new RA messages from coming - terminate_rtadvd $PIDFILE - - # Flush all the entries in the prefix list - atf_check -s exit:0 rump.ndp -P - - $DEBUG && dump_entries - atf_check -s exit:0 -o match:if=shmif0 rump.ndp -r - atf_check -s exit:0 -o empty rump.ndp -p - atf_check -s exit:0 -o match:linkmtu=1300 rump.ndp -n -i shmif0 - atf_check -s exit:0 -o match:"$ONEDAYISH S R" -o not-match:fc00:1: \ - rump.ndp -n -a - atf_check -s exit:0 -o not-match:'fc00:1:' rump.ifconfig shmif0 inet6 - unset RUMP_SERVER - - rump_server_destroy_ifaces -} - -ra_flush_prefix_entries_cleanup() -{ - - $DEBUG && dump - terminate_rtadvd $PIDFILE - cleanup -} - -atf_test_case ra_flush_defrouter_entries cleanup -ra_flush_defrouter_entries_head() -{ - - atf_set "descr" "Tests for flushing default routers (ndp -R)" - atf_set "require.progs" "${RUMP_PROGS}" -} - -ra_flush_defrouter_entries_body() -{ - - rump_server_fs_start $RUMPSRV netinet6 - rump_server_start $RUMPCLI netinet6 - - setup_shmif0 ${RUMPSRV} ${IP6SRV} - setup_shmif0 ${RUMPCLI} ${IP6CLI} - - init_server $RUMPSRV - - create_rtadvdconfig - - RUMP_SERVER=${RUMPCLI} atf_check -s exit:0 -o match:'0 -> 1' \ - rump.sysctl -w net.inet6.ip6.accept_rtadv=1 - - start_rtadvd $RUMPSRV $PIDFILE - await_RA "${RUMPCLI}" - - check_entries $RUMPCLI $RUMPSRV $IP6SRV_PREFIX - - export RUMP_SERVER=${RUMPCLI} - - # Terminate rtadvd to prevent new RA messages from coming - terminate_rtadvd $PIDFILE - - # Flush all the entries in the default router list - atf_check -s exit:0 rump.ndp -R - - $DEBUG && dump_entries - atf_check -s exit:0 -o empty rump.ndp -r - atf_check -s exit:0 -o match:'No advertising router' rump.ndp -p - atf_check -s exit:0 -o match:linkmtu=1300 rump.ndp -n -i shmif0 - atf_check -s exit:0 -o not-match:fc00:1: rump.ndp -n -a - atf_check -s exit:0 -o match:'fc00:1:' rump.ifconfig shmif0 inet6 - unset RUMP_SERVER - - rump_server_destroy_ifaces -} - -ra_flush_defrouter_entries_cleanup() -{ - - $DEBUG && dump - terminate_rtadvd $PIDFILE - cleanup -} - -atf_test_case ra_delete_address cleanup -ra_delete_address_head() -{ - - atf_set "descr" "Tests for deleting auto-configured address" - atf_set "require.progs" "${RUMP_PROGS}" -} - -ra_delete_address_body() -{ - - rump_server_fs_start $RUMPSRV netinet6 - rump_server_start $RUMPCLI netinet6 - - setup_shmif0 ${RUMPSRV} ${IP6SRV} - setup_shmif0 ${RUMPCLI} ${IP6CLI} - - init_server $RUMPSRV - - create_rtadvdconfig - - RUMP_SERVER=${RUMPCLI} atf_check -s exit:0 -o match:'0 -> 1' \ - rump.sysctl -w net.inet6.ip6.accept_rtadv=1 - - start_rtadvd $RUMPSRV $PIDFILE - await_RA "${RUMPCLI}" - - check_entries $RUMPCLI $RUMPSRV $IP6SRV_PREFIX - - export RUMP_SERVER=${RUMPCLI} - $DEBUG && rump.ifconfig shmif0 - atf_check -s exit:0 rump.ifconfig shmif0 inet6 \ - $(rump.ifconfig shmif0 | awk '/AUTOCONF/ {print $2}') delete - unset RUMP_SERVER - - terminate_rtadvd $PIDFILE - - rump_server_destroy_ifaces -} - -ra_delete_address_cleanup() -{ - - $DEBUG && dump - terminate_rtadvd $PIDFILE - cleanup -} - -atf_test_case ra_multiple_routers cleanup -ra_multiple_routers_head() -{ - - atf_set "descr" "Tests for multiple routers" - atf_set "require.progs" "${RUMP_PROGS}" -} - -ra_multiple_routers_body() -{ - local n= - - rump_server_fs_start $RUMPSRV netinet6 - rump_server_fs_start $RUMPSRV3 netinet6 - rump_server_start $RUMPCLI netinet6 - - setup_shmif0 ${RUMPSRV} ${IP6SRV} - setup_shmif0 ${RUMPSRV3} ${IP6SRV3} - setup_shmif0 ${RUMPCLI} ${IP6CLI} - - init_server $RUMPSRV - init_server $RUMPSRV3 - - create_rtadvdconfig - - RUMP_SERVER=${RUMPCLI} atf_check -s exit:0 -o match:'0 -> 1' \ - rump.sysctl -w net.inet6.ip6.accept_rtadv=1 - - start_rtadvd $RUMPSRV $PIDFILE - start_rtadvd $RUMPSRV3 $PIDFILE3 - await_RA "${RUMPCLI}" - await_RA "${RUMPCLI}" - - check_entries $RUMPCLI $RUMPSRV $IP6SRV_PREFIX - check_entries $RUMPCLI $RUMPSRV3 $IP6SRV3_PREFIX - - # Two prefixes are advertised by differnt two routers - n=$(RUMP_SERVER=$RUMPCLI rump.ndp -p | grep 'advertised by' | wc -l) - atf_check_equal $n 2 - - terminate_rtadvd $PIDFILE - terminate_rtadvd $PIDFILE3 - - rump_server_destroy_ifaces -} - -ra_multiple_routers_cleanup() -{ - - $DEBUG && dump - terminate_rtadvd $PIDFILE - terminate_rtadvd $PIDFILE3 - cleanup -} - -atf_test_case ra_multiple_routers_single_prefix cleanup -ra_multiple_routers_single_prefix_head() -{ - - atf_set "descr" "Tests for multiple routers with a single prefix" - atf_set "require.progs" "${RUMP_PROGS}" -} - -ra_multiple_routers_single_prefix_body() -{ - local n= - - rump_server_fs_start $RUMPSRV netinet6 - rump_server_fs_start $RUMPSRV1_2 netinet6 - rump_server_start $RUMPCLI netinet6 - - setup_shmif0 ${RUMPSRV} ${IP6SRV} - setup_shmif0 ${RUMPSRV1_2} ${IP6SRV1_2} - setup_shmif0 ${RUMPCLI} ${IP6CLI} - - init_server $RUMPSRV - init_server $RUMPSRV1_2 - - create_rtadvdconfig - - RUMP_SERVER=${RUMPCLI} atf_check -s exit:0 -o match:'0 -> 1' \ - rump.sysctl -w net.inet6.ip6.accept_rtadv=1 - - start_rtadvd $RUMPSRV $PIDFILE - start_rtadvd $RUMPSRV1_2 $PIDFILE1_2 - await_RA "${RUMPCLI}" - await_RA "${RUMPCLI}" - - check_entries $RUMPCLI $RUMPSRV $IP6SRV_PREFIX - check_entries $RUMPCLI $RUMPSRV1_2 $IP6SRV_PREFIX - - export RUMP_SERVER=$RUMPCLI - # One prefix is advertised by differnt two routers - n=$(rump.ndp -p |grep 'advertised by' |wc -l) - atf_check_equal $n 1 - unset RUMP_SERVER - - terminate_rtadvd $PIDFILE - terminate_rtadvd $PIDFILE1_2 - - rump_server_destroy_ifaces -} - -ra_multiple_routers_single_prefix_cleanup() -{ - - $DEBUG && dump - terminate_rtadvd $PIDFILE - terminate_rtadvd $PIDFILE1_2 - cleanup -} - -atf_test_case ra_multiple_routers_maxifprefixes cleanup -ra_multiple_routers_maxifprefixes_head() -{ - - atf_set "descr" "Tests for exceeding the number of maximum prefixes" - atf_set "require.progs" "${RUMP_PROGS}" -} - -ra_multiple_routers_maxifprefixes_body() -{ - local n= - - rump_server_fs_start $RUMPSRV netinet6 - rump_server_fs_start $RUMPSRV3 netinet6 - rump_server_fs_start $RUMPSRV4 netinet6 - rump_server_start $RUMPCLI netinet6 - - setup_shmif0 ${RUMPSRV} ${IP6SRV} - setup_shmif0 ${RUMPSRV3} ${IP6SRV3} - setup_shmif0 ${RUMPSRV4} ${IP6SRV4} - setup_shmif0 ${RUMPCLI} ${IP6CLI} - - init_server $RUMPSRV - init_server $RUMPSRV3 - init_server $RUMPSRV4 - - create_rtadvdconfig - - RUMP_SERVER=${RUMPCLI} atf_check -s exit:0 -o match:'0.->.1' \ - rump.sysctl -w net.inet6.ip6.accept_rtadv=1 - # Limit the maximum number of prefix entries to 2 - RUMP_SERVER=${RUMPCLI} atf_check -s exit:0 -o match:'16 -> 2' \ - rump.sysctl -w net.inet6.ip6.maxifprefixes=2 - - start_rtadvd $RUMPSRV $PIDFILE - start_rtadvd $RUMPSRV3 $PIDFILE3 - await_RA "${RUMPCLI}" - await_RA "${RUMPCLI}" - - check_entries $RUMPCLI $RUMPSRV $IP6SRV_PREFIX - check_entries $RUMPCLI $RUMPSRV3 $IP6SRV3_PREFIX - - start_rtadvd $RUMPSRV4 $PIDFILE4 - await_RA "${RUMPCLI}" - - $DEBUG && RUMP_SERVER="${RUMPCLI}" dump_entries - # There should remain two prefixes - n=$(RUMP_SERVER=${RUMPCLI} rump.ndp -p | grep 'advertised by' | wc -l) - atf_check_equal $n 2 - # TODO check other conditions - - terminate_rtadvd $PIDFILE - terminate_rtadvd $PIDFILE3 - terminate_rtadvd $PIDFILE4 - - rump_server_destroy_ifaces -} - -ra_multiple_routers_maxifprefixes_cleanup() -{ - - $DEBUG && dump - terminate_rtadvd $PIDFILE - terminate_rtadvd $PIDFILE3 - terminate_rtadvd $PIDFILE4 - cleanup -} - -atf_test_case ra_temporary_address cleanup -ra_temporary_address_head() -{ - - atf_set "descr" "Tests for IPv6 temporary address" - atf_set "require.progs" "${RUMP_PROGS}" -} - -check_echo_request_pkt() -{ - local pkt="$2 > $3: .+ echo request" - - extract_new_packets $1 > ./out - $DEBUG && echo "$pkt" - $DEBUG && cat ./out - atf_check -s exit:0 -o match:"$pkt" cat ./out -} - -ra_temporary_address_body() -{ - local ip_auto= ip_temp= - - rump_server_fs_start $RUMPSRV netinet6 - rump_server_start $RUMPCLI netinet6 - - setup_shmif0 $RUMPSRV $IP6SRV - init_server $RUMPSRV - setup_shmif0 $RUMPCLI $IP6CLI - - RUMP_SERVER=$RUMPCLI atf_check -s exit:0 -o match:'0 -> 1' \ - rump.sysctl -w net.inet6.ip6.accept_rtadv=1 - RUMP_SERVER=$RUMPCLI atf_check -s exit:0 -o match:'0 -> 1' \ - rump.sysctl -w net.inet6.ip6.use_tempaddr=1 - - create_rtadvdconfig - start_rtadvd $RUMPSRV $PIDFILE - await_RA "${RUMPCLI}" - - check_entries $RUMPCLI $RUMPSRV $IP6SRV_PREFIX - - export RUMP_SERVER=$RUMPCLI - - # Check temporary address - atf_check -s exit:0 \ - -o match:"$IP6SRV_PREFIX.+<(TENTATIVE,)?AUTOCONF,TEMPORARY>" \ - rump.ifconfig shmif0 inet6 - - # - # Testing net.inet6.ip6.prefer_tempaddr - # - atf_check -s exit:0 rump.ifconfig -w 10 - $DEBUG && rump.ifconfig shmif0 - ip_auto=$(rump.ifconfig shmif0 | - awk '// {sub(/\/[0-9]*/, ""); print $2;}') - ip_temp=$(rump.ifconfig shmif0 | - awk '// {sub(/\/[0-9]*/, ""); print $2;}') - $DEBUG && echo "AUTO=$ip_auto TEMP=$ip_temp" - - # Ignore old packets - extract_new_packets bus1 > /dev/null - - atf_check -s exit:0 -o ignore rump.ping6 -n -X 2 -c 1 $IP6SRV - # autoconf (non-temporal) address should be used as the source address - check_echo_request_pkt bus1 $ip_auto $IP6SRV - - # Enable net.inet6.ip6.prefer_tempaddr - atf_check -s exit:0 -o match:'0 -> 1' \ - rump.sysctl -w net.inet6.ip6.prefer_tempaddr=1 - - atf_check -s exit:0 -o ignore rump.ping6 -n -X 2 -c 1 $IP6SRV - # autoconf, temporal address should be used as the source address - check_echo_request_pkt bus1 $ip_temp $IP6SRV - - # - # Testing the validation of net.inet6.ip6.temppltime - # - # XXX should move to a better place - atf_check -s not-exit:0 -e match:'Invalid argument' \ - rump.sysctl -w net.inet6.ip6.temppltime=$((600 + 5)) - atf_check -s exit:0 -o match:'86400 -> 606' \ - rump.sysctl -w net.inet6.ip6.temppltime=$((600 + 5 + 1)) - - unset RUMP_SERVER - - terminate_rtadvd $PIDFILE - - rump_server_destroy_ifaces -} - -ra_temporary_address_cleanup() -{ - - $DEBUG && dump - terminate_rtadvd $PIDFILE - cleanup -} - -atf_test_case ra_defrouter_expiration cleanup -ra_defrouter_expiration_head() -{ - - atf_set "descr" "Tests for default router expiration" - atf_set "require.progs" "${RUMP_PROGS}" -} - -ra_defrouter_expiration_body() -{ - local expire_time=5 - - rump_server_fs_start $RUMPSRV netinet6 - rump_server_start $RUMPCLI netinet6 - - setup_shmif0 ${RUMPSRV} ${IP6SRV} - setup_shmif0 ${RUMPCLI} ${IP6CLI} - - init_server $RUMPSRV - - create_rtadvdconfig_rltime $expire_time - - RUMP_SERVER=${RUMPCLI} atf_check -s exit:0 -o match:'0.->.1' \ - rump.sysctl -w net.inet6.ip6.accept_rtadv=1 - - start_rtadvd $RUMPSRV $PIDFILE - await_RA "${RUMPCLI}" - - check_entries $RUMPCLI $RUMPSRV $IP6SRV_PREFIX - - export RUMP_SERVER=${RUMPCLI} - - # Terminate rtadvd to prevent new RA messages from coming - terminate_rtadvd $PIDFILE - - # Wait until the default routers and prefix entries are expired - # XXX need to work out a better way ... this is a race. - # XXX fortunately this race usually ends with the winner we want - # XXX (long odds on - not worth placing a bet...) - sleep $expire_time - - $DEBUG && dump_entries - - # Give nd6_timer a chance to sweep default routers and prefix entries - # XXX Ugh again. - sleep 2 - - $DEBUG && dump_entries - atf_check -s exit:0 -o not-match:if=shmif0 rump.ndp -r - atf_check -s exit:0 -o match:'No advertising router' rump.ndp -p - atf_check -s exit:0 -o match:linkmtu=1300 rump.ndp -n -i shmif0 - atf_check -s exit:0 -o not-match:fc00:1: rump.ndp -n -a - atf_check -s exit:0 -o match:fc00:1: rump.ifconfig shmif0 inet6 - unset RUMP_SERVER - - rump_server_destroy_ifaces -} - -ra_defrouter_expiration_cleanup() -{ - - $DEBUG && dump - terminate_rtadvd $PIDFILE - cleanup -} - -atf_test_case ra_prefix_expiration cleanup -ra_prefix_expiration_head() -{ - - atf_set "descr" "Tests for prefix expiration" - atf_set "require.progs" "${RUMP_PROGS}" -} - -ra_prefix_expiration_body() -{ - local expire_time=5 - - rump_server_fs_start $RUMPSRV netinet6 - rump_server_start $RUMPCLI netinet6 - - setup_shmif0 ${RUMPSRV} ${IP6SRV} - setup_shmif0 ${RUMPCLI} ${IP6CLI} - - init_server $RUMPSRV - - create_rtadvdconfig_vltime "${IP6SRV_PREFIX}:" $expire_time - - RUMP_SERVER=${RUMPCLI} atf_check -s exit:0 -o match:'0 -> 1' \ - rump.sysctl -w net.inet6.ip6.accept_rtadv=1 - - start_rtadvd $RUMPSRV $PIDFILE - await_RA "${RUMPCLI}" - - check_entries $RUMPCLI $RUMPSRV $IP6SRV_PREFIX - - export RUMP_SERVER=${RUMPCLI} - - # Terminate rtadvd to prevent new RA messages from coming - terminate_rtadvd $PIDFILE - - # Wait until the default routers and prefix entries are expired - # XXX need the same better way here too... - sleep $expire_time - - $DEBUG && dump_entries - - # Give nd6_timer a chance to sweep default routers and prefix entries - # XXX and here - sleep 2 - - $DEBUG && dump_entries - atf_check -s exit:0 -o match:if=shmif0 rump.ndp -r - atf_check -s exit:0 -o empty rump.ndp -p - atf_check -s exit:0 -o match:linkmtu=1300 rump.ndp -n -i shmif0 - atf_check -s exit:0 -o match:"$ONEDAYISH S R" -o not-match:fc00:1: \ - rump.ndp -n -a - atf_check -s exit:0 -o not-match:fc00:1: rump.ifconfig shmif0 inet6 - unset RUMP_SERVER - - rump_server_destroy_ifaces -} - -ra_prefix_expiration_cleanup() -{ - - $DEBUG && dump - terminate_rtadvd $PIDFILE - cleanup -} - -atf_init_test_cases() -{ - - atf_add_test_case ra_basic - atf_add_test_case ra_flush_prefix_entries - atf_add_test_case ra_flush_defrouter_entries - atf_add_test_case ra_delete_address - atf_add_test_case ra_multiple_routers - atf_add_test_case ra_multiple_routers_single_prefix - atf_add_test_case ra_multiple_routers_maxifprefixes - atf_add_test_case ra_temporary_address - atf_add_test_case ra_defrouter_expiration - atf_add_test_case ra_prefix_expiration -} diff -r 80f27e12612b usr.sbin/ndp/ndp.8 --- a/usr.sbin/ndp/ndp.8 Tue Apr 21 12:23:13 2020 +0000 +++ b/usr.sbin/ndp/ndp.8 Wed Apr 22 00:54:02 2020 +0100 @@ -28,7 +28,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd February 14, 2018 +.Dd April 19, 2020 .Dt NDP 8 .Os .\" @@ -45,12 +45,6 @@ .Fl a | Fl c | Fl p .Nm ndp .Op Fl nt -.Fl r -.Nm ndp -.Op Fl nt -.Fl H | Fl P | Fl R -.Nm ndp -.Op Fl nt .Fl A Ar wait .Nm ndp .Op Fl nt @@ -65,9 +59,6 @@ .Op Ar expressions ... .Nm ndp .Op Fl nt -.Fl I Op Ar interface | Li delete -.Nm ndp -.Op Fl nt .Fl s Ar nodename etheraddr .Op Li temp .Op Li proxy @@ -138,18 +129,6 @@ .It Fl f Parse the file specified by .Ar filename . -.It Fl H -Harmonize consistency between the routing table and the default router -list; install the top entry of the list into the kernel routing table. -.It Fl I -Shows the default interface used as the default route when -there is no default router. -.It Fl I Ar interface -Specifies the default -.Ar interface -to be used when there is no interface specified even though required. -.It Fl I Li delete -The current default interface will be deleted from the kernel. .It Fl i Ar interface Op Ar expressions ... View ND information for the specified interface. If additional arguments @@ -176,34 +155,12 @@ Turn on or off NUD (Neighbor Unreachability Detection) on the interface. NUD is usually turned on by default. -.It Ic accept_rtadv -Specify whether or not to accept Router Advertisement messages -received on the -.Ar interface . -Note that the kernel does not accept Router Advertisement messages, -even if the flag -.Ic accept_rtadv -is on, unless either the -.Li net.inet6.ip6.accept_rtadv -variable is non-0, or the flag -.Ic override_rtadv -is on. -This flag is set to 1 by default. .It Ic auto_linklocal Specify whether or not to perform automatic link-local address configuration on .Ar interface . This flag is set by .Li net.inet6.ip6.auto_linklocal sysctl variable. -.It Ic override_rtadv -Specify whether or not to override the -.Li net.inet6.ip6.accept_rtadv -variable. -If the flag is on, then it will suffice to set the flag -.Ic accept_rtadv -to make the kernel accept Router Advertisement messages on the -.Ar interface . -This flag is set to 0 by default. .It Ic prefer_source Prefer addresses on the .Ar interface @@ -236,14 +193,6 @@ .El .It Fl n Do not try to resolve numeric addresses to hostnames. -.It Fl P -Flush all the entries in the prefix list. -.It Fl p -Show prefix list. -.It Fl R -Flush all the entries in the default router list. -.It Fl r -Show default router list. .It Fl s Register an NDP entry for a node. The entry will be permanent unless the word diff -r 80f27e12612b usr.sbin/ndp/ndp.c --- a/usr.sbin/ndp/ndp.c Tue Apr 21 12:23:13 2020 +0000 +++ b/usr.sbin/ndp/ndp.c Wed Apr 22 00:54:02 2020 +0100 @@ -131,15 +131,6 @@ __dead static void usage(void); static int rtmsg(int, struct rt_msghdr *); static void ifinfo(char *, int, char **); -static void rtrlist(void); -static void plist(void); -static void pfx_flush(void); -static void rtr_flush(void); -static void harmonize_rtr(void); -#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ -static void getdefif(void); -static void setdefif(char *); -#endif static const char *sec2str(time_t); static char *ether_str(struct sockaddr_dl *); static void ts_print(const struct timeval *); @@ -147,15 +138,6 @@ #define NDP_F_CLEAR 1 #define NDP_F_DELETE 2 -#ifdef ICMPV6CTL_ND6_DRLIST -static const char *rtpref_str[] = { - "medium", /* 00 */ - "high", /* 01 */ - "rsv", /* 10 */ - "low" /* 11 */ -}; -#endif - static int mode = 0; static char *arg = NULL; @@ -164,24 +146,11 @@ { int ch; - while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1) + while ((ch = getopt(argc, argv, "acd:f:i:nstA:")) != -1) switch (ch) { case 'a': case 'c': - case 'p': - case 'r': - case 'H': - case 'P': - case 'R': case 's': - case 'I': - if (mode) { - usage(); - /*NOTREACHED*/ - } - mode = ch; - arg = NULL; - break; case 'd': case 'f': case 'i' : @@ -235,66 +204,13 @@ } delete_one(arg); break; - case 'I': -#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ - if (argc > 1) { - usage(); - /*NOTREACHED*/ - } else if (argc == 1) { - if (strcmp(*argv, "delete") == 0 || - if_nametoindex(*argv)) - setdefif(*argv); - else - errx(1, "invalid interface %s", *argv); - } - getdefif(); /* always call it to print the result */ - break; -#else - errx(1, "not supported yet"); - /*NOTREACHED*/ -#endif - case 'p': - if (argc != 0) { - usage(); - /*NOTREACHED*/ - } - plist(); - break; case 'i': ifinfo(arg, argc, argv); break; - case 'r': - if (argc != 0) { - usage(); - /*NOTREACHED*/ - } - rtrlist(); - break; case 's': if (argc < 2 || argc > 4) usage(); return(set(argc, argv) ? 1 : 0); - case 'H': - if (argc != 0) { - usage(); - /*NOTREACHED*/ - } - harmonize_rtr(); - break; - case 'P': - if (argc != 0) { - usage(); - /*NOTREACHED*/ - } - pfx_flush(); - break; - case 'R': - if (argc != 0) { - usage(); - /*NOTREACHED*/ - } - rtr_flush(); - break; case 0: if (argc != 1) { usage(); @@ -784,9 +700,6 @@ (void)fprintf(stderr, " %s [-nt] -d hostname\n", pn); (void)fprintf(stderr, " %s [-nt] -f filename\n", pn); (void)fprintf(stderr, " %s [-nt] -i interface [flags...]\n", pn); -#ifdef SIOCSDEFIFACE_IN6 - (void)fprintf(stderr, " %s [-nt] -I [interface|delete]\n", pn); -#endif (void)fprintf(stderr, " %s [-nt] -s nodename etheraddr [temp] [proxy]\n", pn); exit(1); @@ -870,9 +783,6 @@ struct in6_ndireq nd; int i, s; u_int32_t newflags; -#ifdef IPV6CTL_USETEMPADDR - u_int8_t nullbuf[8]; -#endif if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) err(1, "socket"); @@ -956,9 +866,6 @@ #undef SETVALUE } - if (!ND.initialized) - errx(1, "%s: not initialized yet", ifname); - if (prog_ioctl(s, SIOCGIFINFO_IN6, &nd) < 0) err(1, "ioctl(SIOCGIFINFO_IN6)"); (void)printf("linkmtu=%d", ND.linkmtu); @@ -968,34 +875,6 @@ ND.basereachable / 1000, ND.basereachable % 1000); (void)printf(", reachable=%ds", ND.reachable); (void)printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); -#ifdef IPV6CTL_USETEMPADDR - (void)memset(nullbuf, 0, sizeof(nullbuf)); - if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) { - int j; - u_int8_t *rbuf; - - for (i = 0; i < 3; i++) { - switch (i) { - case 0: - (void)printf("\nRandom seed(0): "); - rbuf = ND.randomseed0; - break; - case 1: - (void)printf("\nRandom seed(1): "); - rbuf = ND.randomseed1; - break; - case 2: - (void)printf("\nRandom ID: "); - rbuf = ND.randomid; - break; - default: - errx(1, "impossible case for tempaddr display"); - } - for (j = 0; j < 8; j++) - (void)printf("%02x", rbuf[j]); - } - } -#endif if (ND.flags) { (void)printf("\nFlags: "); if ((ND.flags & ND6_IFF_PERFORMNUD)) @@ -1004,14 +883,6 @@ if ((ND.flags & ND6_IFF_IFDISABLED)) (void)printf("disabled "); #endif -#ifdef ND6_IFF_ACCEPT_RTADV - if ((ND.flags & ND6_IFF_ACCEPT_RTADV)) - (void)printf("accept_rtadv "); -#endif -#ifdef ND6_IFF_OVERRIDE_RTADV - if ((ND.flags & ND6_IFF_OVERRIDE_RTADV)) - (void)printf("override_rtadv "); -#endif #ifdef ND6_IFF_AUTO_LINKLOCAL if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL)) (void)printf("auto_linklocal "); @@ -1027,477 +898,6 @@ (void)prog_close(s); } -#ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */ -#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ -#endif - -static void -rtrlist(void) -{ -#ifdef ICMPV6CTL_ND6_DRLIST - int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST }; - char *buf; - struct in6_defrouter *p, *ep; - size_t l; - struct timeval tim; - - if (prog_sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { - err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); - /*NOTREACHED*/ - } - if (l == 0) - return; - buf = malloc(l); - if (!buf) { - err(1, "malloc"); - /*NOTREACHED*/ - } - if (prog_sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { - err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); - /*NOTREACHED*/ - } - - ep = (struct in6_defrouter *)(void *)(buf + l); - for (p = (struct in6_defrouter *)(void *)buf; p < ep; p++) { - int rtpref; - - if (getnameinfo((struct sockaddr *)(void *)&p->rtaddr, - (socklen_t)p->rtaddr.sin6_len, host_buf, sizeof(host_buf), - NULL, 0, (nflag ? NI_NUMERICHOST : 0)) != 0) - (void)strlcpy(host_buf, "?", sizeof(host_buf)); - - (void)printf("%s if=%s", host_buf, - if_indextoname((unsigned int)p->if_index, ifix_buf)); - (void)printf(", flags=%s%s", - p->flags & ND_RA_FLAG_MANAGED ? "M" : "", - p->flags & ND_RA_FLAG_OTHER ? "O" : ""); - rtpref = ((uint32_t)(p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff; - (void)printf(", pref=%s", rtpref_str[rtpref]); - - (void)gettimeofday(&tim, 0); - if (p->expire == 0) - (void)printf(", expire=Never\n"); - else - (void)printf(", expire=%s\n", - sec2str((time_t)(p->expire - tim.tv_sec))); - } - free(buf); -#else - struct in6_drlist dr; - int s, i; - struct timeval time; - - if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { - err(1, "socket"); - /* NOTREACHED */ - } - (void)memset(&dr, 0, sizeof(dr)); - (void)strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */ - if (prog_ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { - err(1, "ioctl(SIOCGDRLST_IN6)"); - /* NOTREACHED */ - } -#define DR dr.defrouter[i] - for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) { - struct sockaddr_in6 sin6; - - (void)memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_len = sizeof(sin6); - sin6.sin6_addr = DR.rtaddr; - (void)getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, - host_buf, sizeof(host_buf), NULL, 0, - (nflag ? NI_NUMERICHOST : 0)); - - (void)printf("%s if=%s", host_buf, - if_indextoname(DR.if_index, ifix_buf)); - (void)printf(", flags=%s%s", - DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", - DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); - gettimeofday(&time, 0); - if (DR.expire == 0) - (void)printf(", expire=Never\n"); - else - (void)printf(", expire=%s\n", - sec2str(DR.expire - time.tv_sec)); - } -#undef DR - (void)prog_close(s); -#endif -} - -static void -plist(void) -{ -#ifdef ICMPV6CTL_ND6_PRLIST - int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST }; - char *buf, *p, *ep; - struct in6_prefix pfx; - size_t l; - struct timeval tim; - const int niflags = NI_NUMERICHOST; - int ninflags = nflag ? NI_NUMERICHOST : 0; - char namebuf[NI_MAXHOST]; - - if (prog_sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { - err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); - /*NOTREACHED*/ - } - buf = malloc(l); - if (!buf) { - err(1, "malloc"); - /*NOTREACHED*/ - } - if (prog_sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { - err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); - /*NOTREACHED*/ - } - - ep = buf + l; - for (p = buf; p < ep; ) { - memcpy(&pfx, p, sizeof(pfx)); - p += sizeof(pfx); - - if (getnameinfo((struct sockaddr*)&pfx.prefix, - (socklen_t)pfx.prefix.sin6_len, namebuf, sizeof(namebuf), - NULL, 0, niflags) != 0) - (void)strlcpy(namebuf, "?", sizeof(namebuf)); - (void)printf("%s/%d if=%s\n", namebuf, pfx.prefixlen, - if_indextoname((unsigned int)pfx.if_index, ifix_buf)); - - (void)gettimeofday(&tim, 0); - /* - * meaning of fields, especially flags, is very different - * by origin. notify the difference to the users. - */ - (void)printf("flags=%s%s%s%s%s", - pfx.raflags.onlink ? "L" : "", - pfx.raflags.autonomous ? "A" : "", - (pfx.flags & NDPRF_ONLINK) != 0 ? "O" : "", - (pfx.flags & NDPRF_DETACHED) != 0 ? "D" : "", -#ifdef NDPRF_HOME - (pfx.flags & NDPRF_HOME) != 0 ? "H" : "" -#else - "" -#endif - ); - if (pfx.vltime == ND6_INFINITE_LIFETIME) - (void)printf(" vltime=infinity"); - else - (void)printf(" vltime=%lu", (unsigned long)pfx.vltime); - if (pfx.pltime == ND6_INFINITE_LIFETIME) - (void)printf(", pltime=infinity"); - else - (void)printf(", pltime=%lu", (unsigned long)pfx.pltime); - if (pfx.expire == 0) - (void)printf(", expire=Never"); - else if (pfx.expire >= tim.tv_sec) - (void)printf(", expire=%s", - sec2str(pfx.expire - tim.tv_sec)); - else - (void)printf(", expired"); - (void)printf(", ref=%d", pfx.refcnt); - (void)printf("\n"); - /* - * "advertising router" list is meaningful only if the prefix - * information is from RA. - */ - if (pfx.advrtrs) { - int j; - struct sockaddr_in6 sin6; - - (void)printf(" advertised by\n"); - for (j = 0; j < pfx.advrtrs && p <= ep; j++) { - struct in6_nbrinfo *nbi; - - memcpy(&sin6, p, sizeof(sin6)); - p += sizeof(sin6); - - if (getnameinfo((struct sockaddr *)&sin6, - (socklen_t)sin6.sin6_len, namebuf, - sizeof(namebuf), NULL, 0, ninflags) != 0) - (void)strlcpy(namebuf, "?", sizeof(namebuf)); - (void)printf(" %s", namebuf); - - nbi = getnbrinfo(&sin6.sin6_addr, - (unsigned int)pfx.if_index, 0); - if (nbi) { - switch (nbi->state) { - case ND6_LLINFO_REACHABLE: - case ND6_LLINFO_STALE: - case ND6_LLINFO_DELAY: - case ND6_LLINFO_PROBE: - (void)printf(" (reachable)\n"); - break; - default: - (void)printf(" (unreachable)\n"); - } - } else - (void)printf(" (no neighbor state)\n"); - } - } else - (void)printf(" No advertising router\n"); - } - free(buf); -#else - struct in6_prlist pr; - int s, i; - struct timeval time; - - (void)gettimeofday(&time, 0); - - if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { - err(1, "socket"); - /* NOTREACHED */ - } - (void)memset(&pr, 0, sizeof(pr)); - (void)strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */ - if (prog_ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { - err(1, "ioctl(SIOCGPRLST_IN6)"); - /* NOTREACHED */ - } -#define PR pr.prefix[i] - for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { - struct sockaddr_in6 p6; - char namebuf[NI_MAXHOST]; - int niflags; - -#ifdef NDPRF_ONLINK - p6 = PR.prefix; -#else - (void)memset(&p6, 0, sizeof(p6)); - p6.sin6_family = AF_INET6; - p6.sin6_len = sizeof(p6); - p6.sin6_addr = PR.prefix; -#endif - - niflags = NI_NUMERICHOST; - if (getnameinfo((struct sockaddr *)&p6, - sizeof(p6), namebuf, sizeof(namebuf), - NULL, 0, niflags)) { - warnx("getnameinfo failed"); - continue; - } - (void)printf("%s/%d if=%s\n", namebuf, PR.prefixlen, - if_indextoname(PR.if_index, ifix_buf)); - - (void)gettimeofday(&time, 0); - /* - * meaning of fields, especially flags, is very different - * by origin. notify the difference to the users. - */ -#if 0 - (void)printf(" %s", - PR.origin == PR_ORIG_RA ? "" : "advertise: "); -#endif -#ifdef NDPRF_ONLINK - (void)printf("flags=%s%s%s%s%s", - PR.raflags.onlink ? "L" : "", - PR.raflags.autonomous ? "A" : "", - (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "", - (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "", -#ifdef NDPRF_HOME - (PR.flags & NDPRF_HOME) != 0 ? "H" : "" -#else - "" -#endif - ); -#else - (void)printf("flags=%s%s", - PR.raflags.onlink ? "L" : "", - PR.raflags.autonomous ? "A" : ""); -#endif - if (PR.vltime == ND6_INFINITE_LIFETIME) - (void)printf(" vltime=infinity"); - else - (void)printf(" vltime=%lu", PR.vltime); - if (PR.pltime == ND6_INFINITE_LIFETIME) - (void)printf(", pltime=infinity"); - else - (void)printf(", pltime=%lu", PR.pltime); - if (PR.expire == 0) - (void)printf(", expire=Never"); - else if (PR.expire >= time.tv_sec) - (void)printf(", expire=%s", - sec2str(PR.expire - time.tv_sec)); - else - (void)printf(", expired"); -#ifdef NDPRF_ONLINK - (void)printf(", ref=%d", PR.refcnt); -#endif -#if 0 - switch (PR.origin) { - case PR_ORIG_RA: - (void)printf(", origin=RA"); - break; - case PR_ORIG_RR: - (void)printf(", origin=RR"); - break; - case PR_ORIG_STATIC: - (void)printf(", origin=static"); - break; - case PR_ORIG_KERNEL: - (void)printf(", origin=kernel"); - break; - default: - (void)printf(", origin=?"); - break; - } -#endif - (void)printf("\n"); - /* - * "advertising router" list is meaningful only if the prefix - * information is from RA. - */ - if (0 && /* prefix origin is almost obsolted */ - PR.origin != PR_ORIG_RA) - ; - else if (PR.advrtrs) { - int j; - (void)printf(" advertised by\n"); - for (j = 0; j < PR.advrtrs; j++) { - struct sockaddr_in6 sin6; - struct in6_nbrinfo *nbi; - - bzero(&sin6, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_len = sizeof(sin6); - sin6.sin6_addr = PR.advrtr[j]; - sin6.sin6_scope_id = PR.if_index; /* XXX */ - (void)getnameinfo((struct sockaddr *)&sin6, - sin6.sin6_len, host_buf, - sizeof(host_buf), NULL, 0, - (nflag ? NI_NUMERICHOST : 0)); - (void)printf(" %s", host_buf); - - nbi = getnbrinfo(&sin6.sin6_addr, - PR.if_index, 0); - if (nbi) { - switch (nbi->state) { - case ND6_LLINFO_REACHABLE: - case ND6_LLINFO_STALE: - case ND6_LLINFO_DELAY: - case ND6_LLINFO_PROBE: - (void)printf(" (reachable)\n"); - break; - default: - (void)printf(" (unreachable)\n"); - } - } else - (void)printf(" (no neighbor state)\n"); - } - if (PR.advrtrs > DRLSTSIZ) - (void)printf(" and %d routers\n", - PR.advrtrs - DRLSTSIZ); - } else - (void)printf(" No advertising router\n"); - } -#undef PR - (void)prog_close(s); -#endif -} - -static void -pfx_flush(void) -{ - int s; - struct in6_ifreq ifr; - - if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, "lo0"); - if (prog_ioctl(s, SIOCSPFXFLUSH_IN6, &ifr) < 0) - err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); - (void)prog_close(s); -} - -static void -rtr_flush(void) -{ - int s; - struct in6_ifreq ifr; - - if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, "lo0"); - if (prog_ioctl(s, SIOCSRTRFLUSH_IN6, &ifr) < 0) - err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); - (void)prog_close(s); -} - -static void -harmonize_rtr(void) -{ - char dummyif[IFNAMSIZ+8]; - int s; - - if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - (void)strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ - if (prog_ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) - err(1, "ioctl(SIOCSNDFLUSH_IN6)"); - - (void)prog_close(s); -} - -#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ -static void -setdefif(char *ifname) -{ - struct in6_ndifreq ndifreq; - unsigned int ifindex; - int s; - - if (strcasecmp(ifname, "delete") == 0) - ifindex = 0; - else { - if ((ifindex = if_nametoindex(ifname)) == 0) - err(1, "failed to resolve i/f index for %s", ifname); - } - - if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - - (void)strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */ - ndifreq.ifindex = ifindex; - - if (prog_ioctl(s, SIOCSDEFIFACE_IN6, &ndifreq) < 0) - err(1, "ioctl(SIOCSDEFIFACE_IN6)"); - - (void)prog_close(s); -} - -static void -getdefif(void) -{ - struct in6_ndifreq ndifreq; - char ifname[IFNAMSIZ+8]; - int s; - - if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - - (void)memset(&ndifreq, 0, sizeof(ndifreq)); - (void)strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */ - - if (prog_ioctl(s, SIOCGDEFIFACE_IN6, &ndifreq) < 0) - err(1, "ioctl(SIOCGDEFIFACE_IN6)"); - - if (ndifreq.ifindex == 0) - (void)printf("No default interface.\n"); - else { - if ((if_indextoname((unsigned int)ndifreq.ifindex, ifname)) == NULL) - err(1, "failed to resolve ifname for index %lu", - ndifreq.ifindex); - (void)printf("ND default interface = %s\n", ifname); - } - - (void)prog_close(s); -} -#endif - static const char * sec2str(time_t total) {