diff --git a/sbin/route/keywords.c b/sbin/route/keywords.c index 5acc887..c8c0f49 100644 --- a/sbin/route/keywords.c +++ b/sbin/route/keywords.c @@ -10,8 +10,8 @@ struct keytab keywords[] = { {"atalk", K_ATALK}, {"blackhole", K_BLACKHOLE}, {"change", K_CHANGE}, - {"cloned", K_CLONED}, - {"cloning", K_CLONING}, + {"cloning", K_CONNECTED}, /* For backward compatibility */ + {"connected", K_CONNECTED}, {"delete", K_DELETE}, {"dst", K_DST}, {"expire", K_EXPIRE}, @@ -51,10 +51,9 @@ struct keytab keywords[] = { {"static", K_STATIC}, {"x25", K_X25}, {"xns", K_XNS}, - {"xresolve", K_XRESOLVE}, {"flushall", K_FLUSHALL}, - {"nocloned", K_NOCLONED}, - {"nocloning", K_NOCLONING}, + {"nocloning", K_NOCONNECTED}, /* For backward compatibility */ + {"noconnected", K_NOCONNECTED}, {"noblackhole", K_NOBLACKHOLE}, {"noreject", K_NOREJECT}, {"mpls", K_MPLS}, diff --git a/sbin/route/keywords.h b/sbin/route/keywords.h index 33700aa..5a43925 100644 --- a/sbin/route/keywords.h +++ b/sbin/route/keywords.h @@ -12,8 +12,9 @@ extern struct keytab { #define K_ATALK 2 #define K_BLACKHOLE 3 #define K_CHANGE 4 -#define K_CLONED 5 -#define K_CLONING 6 +/* #define K_CLONED 5 */ +/* #define K_CLONING 6 */ +#define K_CONNECTED 6 #define K_DELETE 7 #define K_DST 8 #define K_EXPIRE 9 @@ -53,10 +54,11 @@ extern struct keytab { #define K_STATIC 43 #define K_X25 44 #define K_XNS 45 -#define K_XRESOLVE 46 +/* #define K_XRESOLVE 46 */ #define K_FLUSHALL 47 -#define K_NOCLONED 48 -#define K_NOCLONING 49 +/* #define K_NOCLONED 48 */ +/* #define K_NOCLONING 49 */ +#define K_NOCONNECTED 49 #define K_NOBLACKHOLE 50 #define K_NOREJECT 51 #define K_MPLS 52 diff --git a/sbin/route/route.c b/sbin/route/route.c index 0a97c79..6973df4 100644 --- a/sbin/route/route.c +++ b/sbin/route/route.c @@ -516,12 +516,6 @@ newroute(int argc, char *const *argv) case K_NOBLACKHOLE: flags &= ~RTF_BLACKHOLE; break; - case K_CLONED: - flags |= RTF_CLONED; - break; - case K_NOCLONED: - flags &= ~RTF_CLONED; - break; case K_PROTO1: flags |= RTF_PROTO1; break; @@ -531,14 +525,11 @@ newroute(int argc, char *const *argv) case K_PROXY: flags |= RTF_ANNOUNCE; break; - case K_CLONING: - flags |= RTF_CLONING; + case K_CONNECTED: + flags |= RTF_CONNECTED; break; - case K_NOCLONING: - flags &= ~RTF_CLONING; - break; - case K_XRESOLVE: - flags |= RTF_XRESOLVE; + case K_NOCONNECTED: + flags &= ~RTF_CONNECTED; break; case K_STATIC: flags |= RTF_STATIC; diff --git a/sbin/route/rtutil.c b/sbin/route/rtutil.c index 85b3f55..c2a7c6d 100644 --- a/sbin/route/rtutil.c +++ b/sbin/route/rtutil.c @@ -81,14 +81,15 @@ static const struct bits bits[] = { { RTF_MODIFIED, 'M' }, { RTF_DONE, 'd' }, /* Completed -- for routing messages only */ { RTF_MASK, 'm' }, /* Mask Present -- for routing messages only */ - { RTF_CLONING, 'C' }, + /* { RTF_CLONING, 'C' }, */ + { RTF_CONNECTED, 'C' }, { RTF_XRESOLVE, 'X' }, - { RTF_LLINFO, 'L' }, + /* { RTF_LLINFO, 'L' }, */ { RTF_STATIC, 'S' }, { RTF_PROTO1, '1' }, { RTF_PROTO2, '2' }, /* { RTF_PROTO3, '3' }, */ - { RTF_CLONED, 'c' }, + /* { RTF_CLONED, 'c' }, */ /* { RTF_JUMBO, 'J' }, */ { RTF_ANNOUNCE, 'p' }, { RTF_LOCAL, 'l'}, diff --git a/sys/net/if.c b/sys/net/if.c index 8c305e8..d058fc6 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1782,7 +1782,6 @@ p2p_rtrequest(int req, struct rtentry *rt, break; rt->rt_ifp = lo0ifp; - rt->rt_flags &= ~RTF_LLINFO; /* * Make sure to set rt->rt_ifa to the interface @@ -1793,7 +1792,6 @@ p2p_rtrequest(int req, struct rtentry *rt, rt_replace_ifa(rt, ifa); break; case RTM_DELETE: - case RTM_RESOLVE: default: break; } diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c index dff7371..844afda 100644 --- a/sys/net/if_llatbl.c +++ b/sys/net/if_llatbl.c @@ -74,11 +74,62 @@ static void htable_link_entry(struct lltable *llt, struct llentry *lle); static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg); +int +lltable_dump_entry(struct lltable *llt, struct llentry *lle, + struct rt_walkarg *w, struct sockaddr *sa) +{ + struct ifnet *ifp = llt->llt_ifp; + int error = 0; + struct sockaddr_dl sdl; + int size; + struct rt_addrinfo info; + + memset(&info, 0, sizeof(info)); + info.rti_info[RTAX_DST] = sa; + memset(&sdl, 0, sizeof(sdl)); + sdl.sdl_family = AF_LINK; + sdl.sdl_len = sizeof(sdl); + sdl.sdl_index = ifp->if_index; + sdl.sdl_type = ifp->if_type; + if ((lle->la_flags & LLE_VALID) == LLE_VALID) { + sdl.sdl_alen = ifp->if_addrlen; + memcpy(LLADDR(&sdl), &lle->ll_addr, ifp->if_addrlen); + } else { + sdl.sdl_alen = 0; + memset(LLADDR(&sdl), 0, ifp->if_addrlen); + } + info.rti_info[RTAX_GATEWAY] = sstocsa(&sdl); + if (sa->sa_family == AF_INET && lle->la_flags & LLE_PUB) { + struct sockaddr_inarp *sin; + sin = (struct sockaddr_inarp *)sa; + sin->sin_other = SIN_PROXY; + } + if ((error = rt_msg3(RTM_GET, &info, 0, w, &size))) + return error; + if (w->w_where && w->w_tmem && w->w_needed <= 0) { + struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; + + /* Need to copy by myself */ + rtm->rtm_rmx.rmx_expire = + (lle->la_flags & LLE_STATIC) ? 0 : lle->la_expire; + rtm->rtm_flags |= RTF_HOST; /* For ndp */ + rtm->rtm_flags |= (lle->la_flags & LLE_STATIC) ? RTF_STATIC : 0; + if (lle->la_flags & LLE_PUB) + rtm->rtm_flags |= RTF_ANNOUNCE; + if ((error = copyout(rtm, w->w_where, size)) != 0) + w->w_where = NULL; + else + w->w_where = (char *)w->w_where + size; + } + + return error; +} + /* * Dump lle state for a specific address family. */ static int -lltable_dump_af(struct lltable *llt, struct sysctl_req *wr) +lltable_dump_af(struct lltable *llt, struct rt_walkarg *w) { int error; @@ -90,7 +141,7 @@ lltable_dump_af(struct lltable *llt, struct sysctl_req *wr) IF_AFDATA_RLOCK(llt->llt_ifp); error = lltable_foreach_lle(llt, - (llt_foreach_cb_t *)llt->llt_dump_entry, wr); + (llt_foreach_cb_t *)llt->llt_dump_entry, w); IF_AFDATA_RUNLOCK(llt->llt_ifp); return (error); @@ -100,7 +151,7 @@ lltable_dump_af(struct lltable *llt, struct sysctl_req *wr) * Dump arp state for a specific address family. */ int -lltable_sysctl_dumparp(int af, struct sysctl_req *wr) +lltable_sysctl_dumparp(int af, struct rt_walkarg *w) { struct lltable *llt; int error = 0; @@ -108,7 +159,7 @@ lltable_sysctl_dumparp(int af, struct sysctl_req *wr) LLTABLE_RLOCK(); SLIST_FOREACH(llt, &lltables, llt_link) { if (llt->llt_af == af) { - error = lltable_dump_af(llt, wr); + error = lltable_dump_af(llt, w); if (error != 0) goto done; } @@ -378,14 +429,6 @@ lltable_purge_entries(struct lltable *llt) LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) { if (callout_halt(&lle->la_timer, &lle->lle_lock)) LLE_REMREF(lle); -#if defined(__NetBSD__) - /* XXX should have callback? */ - if (lle->la_rt != NULL) { - struct rtentry *rt = lle->la_rt; - lle->la_rt = NULL; - rtfree(rt); - } -#endif llentry_free(lle); } @@ -543,7 +586,8 @@ lltable_get_af(const struct lltable *llt) * Called in route_output when rtm_flags contains RTF_LLDATA. */ int -lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) +lla_rt_output(const u_char rtm_type, const int rtm_flags, const time_t rtm_expire, + struct rt_addrinfo *info, int sdl_index) { const struct sockaddr_dl *dl = satocsdl(info->rti_info[RTAX_GATEWAY]); const struct sockaddr *dst = info->rti_info[RTAX_DST]; @@ -555,10 +599,13 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) KASSERTMSG(dl != NULL && dl->sdl_family == AF_LINK, "invalid dl"); - ifp = if_byindex(dl->sdl_index); + if (sdl_index != 0) + ifp = if_byindex(sdl_index); + else + ifp = if_byindex(dl->sdl_index); if (ifp == NULL) { log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", - __func__, dl->sdl_index); + __func__, sdl_index != 0 ? sdl_index : dl->sdl_index); return EINVAL; } @@ -574,10 +621,22 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) error = 0; - switch (rtm->rtm_type) { + switch (rtm_type) { case RTM_ADD: /* Add static LLE */ IF_AFDATA_WLOCK(ifp); + lle = lla_lookup(llt, 0, dst); + + /* Cannot overwrite an existing static entry */ + if (lle != NULL && + (lle->la_flags & LLE_STATIC || lle->la_expire == 0)) { + LLE_RUNLOCK(lle); + IF_AFDATA_WUNLOCK(ifp); + return EEXIST; + } + if (lle != NULL) + LLE_RUNLOCK(lle); + lle = lla_create(llt, 0, dst); if (lle == NULL) { IF_AFDATA_WUNLOCK(ifp); @@ -586,7 +645,7 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) memcpy(&lle->ll_addr, CLLADDR(dl), ifp->if_addrlen); - if ((rtm->rtm_flags & RTF_ANNOUNCE)) + if ((rtm_flags & RTF_ANNOUNCE)) lle->la_flags |= LLE_PUB; lle->la_flags |= LLE_VALID; #ifdef INET6 @@ -600,11 +659,11 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) * NB: arp and ndp always set (RTF_STATIC | RTF_HOST) */ - if (rtm->rtm_rmx.rmx_expire == 0) { + if (rtm_expire == 0) { lle->la_flags |= LLE_STATIC; lle->la_expire = 0; } else - lle->la_expire = rtm->rtm_rmx.rmx_expire; + lle->la_expire = rtm_expire; laflags = lle->la_flags; LLE_WUNLOCK(lle); IF_AFDATA_WUNLOCK(ifp); diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h index bb1135e..c462121 100644 --- a/sys/net/if_llatbl.h +++ b/sys/net/if_llatbl.h @@ -44,6 +44,7 @@ struct ifnet; struct sysctl_req; struct rt_msghdr; struct rt_addrinfo; +struct rt_walkarg; struct llentry; LIST_HEAD(llentries, llentry); @@ -99,8 +100,6 @@ struct llentry { #define ln_expire la_expire #define ln_asked la_asked #define ln_hold la_hold - struct rtentry *la_rt; -#define ln_rt la_rt void *la_opaque; /* For tokenring */ #endif }; @@ -197,7 +196,7 @@ typedef int (llt_delete_t)(struct lltable *, u_int flags, typedef void (llt_prefix_free_t)(struct lltable *, const struct sockaddr *prefix, const struct sockaddr *mask, u_int flags); typedef int (llt_dump_entry_t)(struct lltable *, struct llentry *, - struct sysctl_req *); + struct rt_walkarg *); typedef uint32_t (llt_hash_t)(const struct llentry *, uint32_t); typedef int (llt_match_prefix_t)(const struct sockaddr *, const struct sockaddr *, u_int, struct llentry *); @@ -259,7 +258,9 @@ void lltable_prefix_free(int, struct sockaddr *, struct sockaddr *, u_int); void lltable_drain(int); void lltable_purge_entries(struct lltable *); -int lltable_sysctl_dumparp(int, struct sysctl_req *); +int lltable_sysctl_dumparp(int, struct rt_walkarg *); +int lltable_dump_entry(struct lltable *, struct llentry *, + struct rt_walkarg *, struct sockaddr *); size_t llentry_free(struct llentry *); struct llentry *llentry_alloc(struct ifnet *, struct lltable *, @@ -309,6 +310,7 @@ lla_delete(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) } -int lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *); +int lla_rt_output(const u_char, const int, const time_t, + struct rt_addrinfo *info, int); #endif /* _NET_IF_LLATBL_H_ */ diff --git a/sys/net/route.c b/sys/net/route.c index c0cdccc..5ecce06 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -144,8 +144,6 @@ static int _rtcache_debug = 0; static kauth_listener_t route_listener; static int rtdeletemsg(struct rtentry *); -static int rtflushclone1(struct rtentry *, void *); -static void rtflushclone(sa_family_t family, struct rtentry *); static void rtflushall(int); static void rt_maskedcopy(const struct sockaddr *, @@ -356,6 +354,36 @@ rtcache(struct route *ro) rtcache_invariants(ro); } +#ifdef RT_DEBUG +static void +dump_rt(const struct rtentry *rt) +{ + char buf[512]; + + aprint_normal("rt: "); + aprint_normal("p=%p ", rt); + if (rt->_rt_key == NULL) { + aprint_normal("dst=(NULL) "); + } else { + sockaddr_format(rt->_rt_key, buf, sizeof(buf)); + aprint_normal("dst=%s ", buf); + } + if (rt->rt_gateway == NULL) { + aprint_normal("gw=(NULL) "); + } else { + sockaddr_format(rt->_rt_key, buf, sizeof(buf)); + aprint_normal("gw=%s ", buf); + } + aprint_normal("flags=%x ", rt->rt_flags); + if (rt->rt_ifp == NULL) { + aprint_normal("if=(NULL) "); + } else { + aprint_normal("if=%s ", rt->rt_ifp->if_xname); + } + aprint_normal("\n"); +} +#endif /* RT_DEBUG */ + /* * Packet routing routines. If success, refcnt of a returned rtentry * will be incremented. The caller has to rtfree it by itself. @@ -363,49 +391,33 @@ rtcache(struct route *ro) struct rtentry * rtalloc1(const struct sockaddr *dst, int report) { - rtbl_t *rtbl = rt_gettable(dst->sa_family); + rtbl_t *rtbl; struct rtentry *rt; struct rtentry *newrt = NULL; struct rt_addrinfo info; int s = splsoftnet(), err = 0, msgtype = RTM_MISS; - if (rtbl != NULL && (rt = rt_matchaddr(rtbl, dst)) != NULL) { - newrt = rt; - if (report && (rt->rt_flags & RTF_CLONING)) { - err = rtrequest(RTM_RESOLVE, dst, NULL, NULL, 0, - &newrt); - if (err) { - newrt = rt; - rt->rt_refcnt++; - goto miss; - } - KASSERT(newrt != NULL); - rt = newrt; - if (rt->rt_flags & RTF_XRESOLVE) { - msgtype = RTM_RESOLVE; - goto miss; - } - /* Inform listeners of the new route */ - memset(&info, 0, sizeof(info)); - info.rti_info[RTAX_DST] = rt_getkey(rt); - info.rti_info[RTAX_NETMASK] = rt_mask(rt); - info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; - if (rt->rt_ifp != NULL) { - info.rti_info[RTAX_IFP] = - rt->rt_ifp->if_dl->ifa_addr; - info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr; - } - rt_missmsg(RTM_ADD, &info, rt->rt_flags, 0); - } else - rt->rt_refcnt++; - } else { + rtbl = rt_gettable(dst->sa_family); + if (rtbl == NULL) { rtstat.rts_unreach++; - miss: if (report) { - memset((void *)&info, 0, sizeof(info)); - info.rti_info[RTAX_DST] = dst; - rt_missmsg(msgtype, &info, 0, err); - } + goto miss; } + + rt = rt_matchaddr(rtbl, dst); + if (rt == NULL) { + rtstat.rts_unreach++; + goto miss; + } + rt->rt_refcnt++; + + newrt = rt; +miss: + if (report) { + memset((void *)&info, 0, sizeof(info)); + info.rti_info[RTAX_DST] = dst; + rt_missmsg(msgtype, &info, 0, err); + } + splx(s); return newrt; } @@ -589,28 +601,6 @@ rtdeletemsg(struct rtentry *rt) return error; } -static int -rtflushclone1(struct rtentry *rt, void *arg) -{ - struct rtentry *parent; - - parent = (struct rtentry *)arg; - if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent) - rtdeletemsg(rt); - return 0; -} - -static void -rtflushclone(sa_family_t family, struct rtentry *parent) -{ - -#ifdef DIAGNOSTIC - if (!parent || (parent->rt_flags & RTF_CLONING) == 0) - panic("rtflushclone: called with a non-cloning route"); -#endif - rt_walktree(family, rtflushclone1, (void *)parent); -} - struct ifaddr * ifa_ifwithroute(int flags, const struct sockaddr *dst, const struct sockaddr *gateway) @@ -754,7 +744,7 @@ rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt) { int s = splsoftnet(); int error = 0, rc; - struct rtentry *rt, *crt; + struct rtentry *rt; rtbl_t *rtbl; struct ifaddr *ifa, *ifa2; struct sockaddr_storage maskeddst; @@ -777,20 +767,12 @@ rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt) } if ((rt = rt_lookup(rtbl, dst, netmask)) == NULL) senderr(ESRCH); - if ((rt->rt_flags & RTF_CLONING) != 0) { - /* clean up any cloned children */ - rtflushclone(dst->sa_family, rt); - } if ((rt = rt_deladdr(rtbl, dst, netmask)) == NULL) senderr(ESRCH); if (rt->rt_gwroute) { rtfree(rt->rt_gwroute); rt->rt_gwroute = NULL; } - if (rt->rt_parent) { - rt->rt_parent->rt_refcnt--; - rt->rt_parent = NULL; - } rt->rt_flags &= ~RTF_UP; if ((ifa = rt->rt_ifa)) { if (ifa->ifa_flags & IFA_ROUTE && @@ -814,23 +796,10 @@ rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt) } break; - case RTM_RESOLVE: - if (ret_nrt == NULL || (rt = *ret_nrt) == NULL) - senderr(EINVAL); - if ((rt->rt_flags & RTF_CLONING) == 0) - senderr(EINVAL); - ifa = rt->rt_ifa; - flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC); - flags |= RTF_CLONED; - gateway = rt->rt_gateway; - flags |= RTF_HOST; - goto makeroute; - case RTM_ADD: if (info->rti_ifa == NULL && (error = rt_getifa(info))) senderr(error); ifa = info->rti_ifa; - makeroute: /* Already at splsoftnet() so pool_get/pool_put are safe */ rt = pool_get(&rtentry_pool, PR_NOWAIT); if (rt == NULL) @@ -864,28 +833,11 @@ rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt) rt->rt_ifp = ifa2->ifa_ifp; else rt->rt_ifp = ifa->ifa_ifp; - if (req == RTM_RESOLVE) { - rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ - rt->rt_parent = *ret_nrt; - rt->rt_parent->rt_refcnt++; - } RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); rc = rt_addaddr(rtbl, rt, netmask); RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); - if (rc != 0 && (crt = rtalloc1(rt_getkey(rt), 0)) != NULL) { - /* overwrite cloned route */ - if ((crt->rt_flags & RTF_CLONED) != 0) { - rtdeletemsg(crt); - rc = rt_addaddr(rtbl, rt, netmask); - } - rtfree(crt); - RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); - } - RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key); if (rc != 0) { ifafree(ifa); - if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent) - rtfree(rt->rt_parent); if (rt->rt_gwroute) rtfree(rt->rt_gwroute); rt_destroy(rt); @@ -900,10 +852,6 @@ rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt) *ret_nrt = rt; rt->rt_refcnt++; } - if ((rt->rt_flags & RTF_CLONING) != 0) { - /* clean up any cloned children */ - rtflushclone(dst->sa_family, rt); - } rtflushall(dst->sa_family); break; case RTM_GET: @@ -1050,6 +998,7 @@ rtinit(struct ifaddr *ifa, int cmd, int flags) info.rti_flags = flags | ifa->ifa_flags; info.rti_info[RTAX_DST] = dst; info.rti_info[RTAX_GATEWAY] = ifa->ifa_addr; + /* * XXX here, it seems that we are assuming that ifa_netmask is NULL * for RTF_HOST. bsdi4 passes NULL explicitly (via intermediate @@ -1119,6 +1068,10 @@ rt_ifa_addlocal(struct ifaddr *ifa) /* If there is no loopback entry, allocate one. */ rt = rtalloc1(ifa->ifa_addr, 0); +#ifdef RT_DEBUG + if (rt != NULL) + dump_rt(rt); +#endif if (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 || (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) { @@ -1128,7 +1081,7 @@ rt_ifa_addlocal(struct ifaddr *ifa) memset(&info, 0, sizeof(info)); info.rti_flags = RTF_HOST | RTF_LOCAL; if (!(ifa->ifa_ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))) - info.rti_flags |= RTF_LLINFO; + info.rti_flags |= RTF_LLDATA; info.rti_info[RTAX_DST] = ifa->ifa_addr; info.rti_info[RTAX_GATEWAY] = (const struct sockaddr *)ifa->ifa_ifp->if_sadl; @@ -1138,8 +1091,12 @@ rt_ifa_addlocal(struct ifaddr *ifa) if (nrt && ifa != nrt->rt_ifa) rt_replace_ifa(nrt, ifa); rt_newaddrmsg(RTM_ADD, ifa, e, nrt); - if (nrt != NULL) + if (nrt != NULL) { +#ifdef RT_DEBUG + dump_rt(nrt); +#endif rtfree(nrt); + } } else { e = 0; rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL); diff --git a/sys/net/route.h b/sys/net/route.h index a4aa070..7c9f95f 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -145,13 +145,18 @@ struct ortentry { #define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */ #define RTF_DONE 0x40 /* message confirmed */ #define RTF_MASK 0x80 /* subnet mask present */ -#define RTF_CLONING 0x100 /* generate new routes on use */ -#define RTF_XRESOLVE 0x200 /* external daemon resolves name */ -#define RTF_LLINFO 0x400 /* generated by ARP or NDP */ +#define RTF_CLONING 0x100 /* DEPRECATED - exists ONLY for backward + compatibility */ +#define RTF_CONNECTED 0x100 /* host address route */ +#define RTF_XRESOLVE 0x200 /* DEPRECATED - exists ONLY for backward + compatibility */ +#define RTF_LLINFO 0x400 /* DEPRECATED - exists ONLY for backward + compatibility */ #define RTF_LLDATA 0x400 /* used by apps to add/del L2 entries */ #define RTF_STATIC 0x800 /* manually added */ #define RTF_BLACKHOLE 0x1000 /* just discard pkts (during updates) */ -#define RTF_CLONED 0x2000 /* this is a cloned route */ +#define RTF_CLONED 0x2000 /* DEPRECATED - exists ONLY for backward + compatibility */ #define RTF_PROTO2 0x4000 /* protocol specific routing flag */ #define RTF_PROTO1 0x8000 /* protocol specific routing flag */ #define RTF_SRC 0x10000 /* route has fixed source address */ @@ -217,7 +222,8 @@ struct rt_msghdr { #define RTM_LOCK 0x8 /* fix specified metrics */ #define RTM_OLDADD 0x9 /* caused by SIOCADDRT */ #define RTM_OLDDEL 0xa /* caused by SIOCDELRT */ -#define RTM_RESOLVE 0xb /* req to resolve dst to LL addr */ +#define RTM_RESOLVE 0xb /* DEPRECATED - exists ONLY for backward + compatibility */ #define RTM_NEWADDR 0xc /* address being added to iface */ #define RTM_DELADDR 0xd /* address being removed from iface */ #define RTM_OOIFINFO 0xe /* Old (pre-1.5) RTM_IFINFO message */ @@ -504,6 +510,7 @@ void rt_ifmsg(struct ifnet *); void rt_missmsg(int, const struct rt_addrinfo *, int, int); struct mbuf * rt_msg1(int, struct rt_addrinfo *, void *, int); +int rt_msg3(int, struct rt_addrinfo *, void *, struct rt_walkarg *, int *); void rt_newaddrmsg(int, struct ifaddr *, int, struct rtentry *); void route_enqueue(struct mbuf *, int); diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index 5ccc653..c775b94 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -81,14 +81,16 @@ __KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.177 2016/01/21 15:41:29 riastradh Exp $ #include #include #include -#ifdef RTSOCK_DEBUG -#include -#endif /* RTSOCK_DEBUG */ #include +#include +#include #include #include +#include +#include + #include #ifdef SCTP @@ -153,10 +155,10 @@ struct route_info COMPATNAME(route_info) = { static void COMPATNAME(route_init)(void); static int COMPATNAME(route_output)(struct mbuf *, struct socket *); -static int rt_msg2(int, struct rt_addrinfo *, void *, struct rt_walkarg *, int *); static int rt_xaddrs(u_char, const char *, const char *, struct rt_addrinfo *); static struct mbuf *rt_makeifannouncemsg(struct ifnet *, int, int, struct rt_addrinfo *); +static int rt_msg2(int, struct rt_addrinfo *, void *, struct rt_walkarg *, int *); static void rt_setmetrics(int, const struct rt_xmsghdr *, struct rtentry *); static void rtm_setmetrics(const struct rtentry *, struct rt_xmsghdr *); static void sysctl_net_route_setup(struct sysctllog **); @@ -421,6 +423,68 @@ COMPATNAME(route_purgeif)(struct socket *so, struct ifnet *ifp) return EOPNOTSUPP; } +static int +route_get_sdl_index(struct rt_addrinfo *info, int *sdl_index) +{ + struct rtentry *nrt; + int error; + + error = rtrequest1(RTM_GET, info, &nrt); + if (error != 0) + return error; + /* + * nrt->rt_ifp->if_index may not be correct + * due to changing to ifplo0. + */ + *sdl_index = satosdl(nrt->rt_gateway)->sdl_index; + rtfree(nrt); + + return 0; +} + +static void +route_get_sdl(const struct ifnet *ifp, const struct sockaddr *dst, + struct sockaddr_dl *sdl, int *flags) +{ + struct llentry *la = NULL; + + KASSERT(ifp != NULL); + + memset(sdl, 0, sizeof(*sdl)); + sdl->sdl_family = AF_LINK; + sdl->sdl_len = sizeof(*sdl); + sdl->sdl_index = ifp->if_index; + sdl->sdl_type = ifp->if_type; + + IF_AFDATA_RLOCK(ifp); + switch (dst->sa_family) { + case AF_INET: + la = lla_lookup(LLTABLE(ifp), 0, dst); + break; + case AF_INET6: + la = lla_lookup(LLTABLE6(ifp), 0, dst); + break; + default: + KASSERTMSG(0, "Invalid AF=%d\n", dst->sa_family); + break; + } + IF_AFDATA_RUNLOCK(ifp); + + if (LLE_IS_VALID(la) && + (la->la_flags & LLE_VALID) == LLE_VALID) { + sdl->sdl_alen = ifp->if_addrlen; + memcpy(LLADDR(sdl), &la->ll_addr, ifp->if_addrlen); + } else { + sdl->sdl_alen = 0; + memset(LLADDR(sdl), 0, ifp->if_addrlen); + } + + if (la != NULL) { + *flags = la->la_flags; + LLE_RUNLOCK(la); + } +} + /*ARGSUSED*/ int COMPATNAME(route_output)(struct mbuf *m, struct socket *so) @@ -435,6 +499,9 @@ COMPATNAME(route_output)(struct mbuf *m, struct socket *so) struct ifnet *ifp = NULL; struct ifaddr *ifa = NULL; sa_family_t family; + bool is_ll = false; + int ll_flags = 0; + struct sockaddr_dl sdl; #define senderr(e) do { error = e; goto flush;} while (/*CONSTCOND*/ 0) if (m == NULL || ((m->m_len < sizeof(int32_t)) && @@ -496,6 +563,43 @@ COMPATNAME(route_output)(struct mbuf *m, struct socket *so) if (info.rti_info[RTAX_GATEWAY] == NULL) { senderr(EINVAL); } + /* support for new ARP code with keeping backcompat */ + if (info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) { + int sdl_index = + satocsdl(info.rti_info[RTAX_GATEWAY])->sdl_index; + + /* + * Old arp binaries don't set the sdl_index + * so we have to complement it. + */ + if (sdl_index == 0) { + error = route_get_sdl_index(&info, &sdl_index); + if (error != 0) + goto fallback; + } else if ( + info.rti_info[RTAX_DST]->sa_family == AF_INET) { + /* + * XXX workaround for SIN_PROXY case; proxy arp + * entry should be in an interface that has + * a network route including the destination, + * not a local (link) route that may not be a + * desired place, for example a tap. + */ + const struct sockaddr_inarp *sina = + (const struct sockaddr_inarp *) + info.rti_info[RTAX_DST]; + if (sina->sin_other & SIN_PROXY) { + error = route_get_sdl_index(&info, + &sdl_index); + if (error != 0) + goto fallback; + } + } + error = lla_rt_output(rtm->rtm_type, rtm->rtm_flags, + rtm->rtm_rmx.rmx_expire, &info, sdl_index); + break; + } + fallback: error = rtrequest1(rtm->rtm_type, &info, &saved_nrt); if (error == 0) { rt_setmetrics(rtm->rtm_inits, rtm, saved_nrt); @@ -504,6 +608,14 @@ COMPATNAME(route_output)(struct mbuf *m, struct socket *so) break; case RTM_DELETE: + /* support for new ARP code */ + if (info.rti_info[RTAX_GATEWAY] && + (info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) && + (rtm->rtm_flags & RTF_LLDATA) != 0) { + error = lla_rt_output(rtm->rtm_type, rtm->rtm_flags, + rtm->rtm_rmx.rmx_expire, &info, 0); + break; + } error = rtrequest1(rtm->rtm_type, &info, &saved_nrt); if (error == 0) { rt = saved_nrt; @@ -531,6 +643,16 @@ COMPATNAME(route_output)(struct mbuf *m, struct socket *so) senderr(ETOOMANYREFS); } + /* XXX workaround when rt is a cloning route */ + if (rtm->rtm_type == RTM_GET && + sockaddr_cmp(rt_getkey(rt), info.rti_info[RTAX_DST]) != 0) { + route_get_sdl(rt->rt_ifp, info.rti_info[RTAX_DST], &sdl, + &ll_flags); + info.rti_info[RTAX_GATEWAY] = sstocsa(&sdl); + is_ll = true; + goto skip; + } + switch (rtm->rtm_type) { case RTM_GET: report: @@ -538,6 +660,7 @@ COMPATNAME(route_output)(struct mbuf *m, struct socket *so) info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; info.rti_info[RTAX_NETMASK] = rt_mask(rt); info.rti_info[RTAX_TAG] = rt_gettag(rt); + skip: if ((rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) == 0) ; else if ((ifp = rt->rt_ifp) != NULL) { @@ -587,6 +710,10 @@ COMPATNAME(route_output)(struct mbuf *m, struct socket *so) rtm->rtm_flags = rt->rt_flags; rtm_setmetrics(rt, rtm); rtm->rtm_addrs = info.rti_addrs; + if (is_ll) { + rtm->rtm_flags |= RTF_LLDATA; + rtm->rtm_flags |= (ll_flags & LLE_STATIC) ? RTF_STATIC : 0; + } break; case RTM_CHANGE: @@ -974,6 +1101,15 @@ again: return 0; } +#ifndef COMPAT_RTSOCK +int +rt_msg3(int type, struct rt_addrinfo *rtinfo, void *cpv, struct rt_walkarg *w, + int *lenp) +{ + return rt_msg2(type, rtinfo, cpv, w, lenp); +} +#endif + /* * This routine is called to generate a message from the routing * socket indicating that a redirect has occurred, a routing lookup @@ -1398,6 +1534,19 @@ again: case NET_RT_DUMP: case NET_RT_FLAGS: + /* + * take care of llinfo entries, the caller must + * specify an AF + */ + if (w.w_op == NET_RT_FLAGS && + (w.w_arg == 0 || w.w_arg & RTF_LLDATA)) { + if (af != 0) + error = lltable_sysctl_dumparp(af, &w); + else + error = EINVAL; + break; + } + for (i = 1; i <= AF_MAX; i++) if ((af == 0 || af == i) && (error = rt_walktree(i, sysctl_dumpentry, &w))) diff --git a/sys/netinet/if_arp.c b/sys/netinet/if_arp.c index 5929a7b..e24f13d 100644 --- a/sys/netinet/if_arp.c +++ b/sys/netinet/if_arp.c @@ -159,11 +159,12 @@ static void arp_init(void); static struct sockaddr *arp_setgate(struct rtentry *, struct sockaddr *, const struct sockaddr *); -static void arptfree(struct rtentry *); static void arptimer(void *); static void arp_settimer(struct llentry *, int); static struct llentry *arplookup(struct ifnet *, struct mbuf *, - const struct in_addr *, int, int, int, struct rtentry *); + const struct in_addr *, const struct sockaddr *, int); +static struct llentry *arpcreate(struct ifnet *, struct mbuf *, + const struct in_addr *, const struct sockaddr *, int); static void in_arpinput(struct mbuf *); static void in_revarpinput(struct mbuf *); static void revarprequest(struct ifnet *); @@ -187,7 +188,6 @@ struct ifqueue arpintrq = { .ifq_maxlen = 50, .ifq_drops = 0, }; -static int arp_inuse, arp_allocated; static int arp_maxtries = 5; static int useloopback = 1; /* use loopback interface for local traffic */ @@ -320,7 +320,6 @@ arptimer(void *arg) { struct llentry *lle = arg; struct ifnet *ifp; - struct rtentry *rt; if (lle == NULL) return; @@ -349,19 +348,12 @@ arptimer(void *arg) return; } ifp = lle->lle_tbl->llt_ifp; - rt = lle->la_rt; - lle->la_rt = NULL; callout_stop(&lle->la_timer); /* XXX: LOR avoidance. We still have ref on lle. */ LLE_WUNLOCK(lle); - if (rt != NULL) { - /* We have to call arptfree w/o IF_AFDATA_LOCK */ - arptfree(rt); - } - IF_AFDATA_LOCK(ifp); LLE_WLOCK(lle); @@ -408,10 +400,9 @@ arp_setgate(struct rtentry *rt, struct sockaddr *gate, */ if ((rt->rt_flags & RTF_HOST) == 0 && netmask != NULL && satocsin(netmask)->sin_addr.s_addr != 0xffffffff) - rt->rt_flags |= RTF_CLONING; - if (rt->rt_flags & RTF_CLONING || - ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && !rt->rt_llinfo)) - { + rt->rt_flags |= RTF_CONNECTED; + + if ((rt->rt_flags & (RTF_CONNECTED | RTF_LOCAL))) { union { struct sockaddr sa; struct sockaddr_storage ss; @@ -459,11 +450,9 @@ void arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) { struct sockaddr *gate = rt->rt_gateway; - struct llentry *la = NULL; struct in_ifaddr *ia; struct ifaddr *ifa; struct ifnet *ifp = rt->rt_ifp; - int flags = 0; if (req == RTM_LLINFO_UPD) { struct in_addr *in; @@ -518,19 +507,14 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) return; } - IF_AFDATA_RLOCK(ifp); - la = lla_lookup(LLTABLE(ifp), flags, rt_getkey(rt)); - IF_AFDATA_RUNLOCK(ifp); - switch (req) { case RTM_SETGATE: gate = arp_setgate(rt, gate, info->rti_info[RTAX_NETMASK]); break; case RTM_ADD: gate = arp_setgate(rt, gate, info->rti_info[RTAX_NETMASK]); - if (rt->rt_flags & RTF_CLONING || - ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && !la)) - { + if ((rt->rt_flags & RTF_CONNECTED) || + (rt->rt_flags & RTF_LOCAL)) { /* * Give this route an expiration time, even though * it's a "permanent" route, so that routes cloned @@ -569,7 +553,7 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) } #endif } - if (rt->rt_flags & RTF_CLONING) + if (rt->rt_flags & RTF_CONNECTED) break; } /* Announce a new entry if requested. */ @@ -586,8 +570,7 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) &satocsin(rt_getkey(rt))->sin_addr, CLLADDR(satocsdl(gate))); } - /*FALLTHROUGH*/ - case RTM_RESOLVE: + if (gate->sa_family != AF_LINK || gate->sa_len < sockaddr_dl_measure(0, ifp->if_addrlen)) { log(LOG_DEBUG, "arp_rtrequest: bad gateway value\n"); @@ -596,8 +579,6 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) satosdl(gate)->sdl_type = ifp->if_type; satosdl(gate)->sdl_index = ifp->if_index; - if (la != NULL) - break; /* This happens on a route change */ /* If the route is for a broadcast address mark it as such. * This way we can avoid an expensive call to in_broadcast() @@ -614,121 +595,25 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) INADDR_TO_IA(satocsin(rt_getkey(rt))->sin_addr, ia); while (ia && ia->ia_ifp != ifp) NEXT_IA_WITH_SAME_ADDR(ia); - if (ia) { - /* - * This test used to be - * if (lo0ifp->if_flags & IFF_UP) - * It allowed local traffic to be forced through - * the hardware by configuring the loopback down. - * However, it causes problems during network - * configuration for boards that can't receive - * packets they send. It is now necessary to clear - * "useloopback" and remove the route to force - * traffic out to the hardware. - * - * In 4.4BSD, the above "if" statement checked - * rt->rt_ifa against rt_getkey(rt). It was changed - * to the current form so that we can provide a - * better support for multiple IPv4 addresses on a - * interface. - */ - rt->rt_expire = 0; - if (sockaddr_dl_init(satosdl(gate), gate->sa_len, - ifp->if_index, ifp->if_type, NULL, 0, - CLLADDR(ifp->if_sadl), ifp->if_addrlen) == NULL) { - panic("%s(%s): sockaddr_dl_init cannot fail", - __func__, ifp->if_xname); - } - if (useloopback) { - ifp = rt->rt_ifp = lo0ifp; - rt->rt_rmx.rmx_mtu = 0; - } - rt->rt_flags |= RTF_LOCAL; - /* - * make sure to set rt->rt_ifa to the interface - * address we are using, otherwise we will have trouble - * with source address selection. - */ - ifa = &ia->ia_ifa; - if (ifa != rt->rt_ifa) - rt_replace_ifa(rt, ifa); + + if (ia == NULL) + break; + + rt->rt_expire = 0; + if (useloopback) { + ifp = rt->rt_ifp = lo0ifp; + rt->rt_rmx.rmx_mtu = 0; } - + rt->rt_flags |= RTF_LOCAL; /* - * Case 2: This route may come from cloning, or a manual route - * add with a LL address. + * make sure to set rt->rt_ifa to the interface + * address we are using, otherwise we will have trouble + * with source address selection. */ - flags = LLE_EXCLUSIVE; - if ((rt->rt_flags & RTF_CLONING) != 0) - flags |= LLE_IFADDR; - - IF_AFDATA_WLOCK(ifp); - la = lla_create(LLTABLE(ifp), flags, rt_getkey(rt)); - IF_AFDATA_WUNLOCK(ifp); - - if (la == NULL) { - log(LOG_DEBUG, "%s: lla_create failed\n", - __func__); - rt->rt_llinfo = NULL; - break; - } - rt->rt_llinfo = la; - LLE_ADDREF(la); - la->la_rt = rt; - rt->rt_refcnt++; - rt->rt_flags |= RTF_LLINFO; - arp_inuse++, arp_allocated++; - arp_init_llentry(ifp, la); - - LLE_WUNLOCK(la); - la = NULL; - + ifa = &ia->ia_ifa; + if (ifa != rt->rt_ifa) + rt_replace_ifa(rt, ifa); break; - - case RTM_DELETE: - if (la == NULL) - break; - arp_inuse--; - rt->rt_llinfo = NULL; - rt->rt_flags &= ~RTF_LLINFO; - - /* Have to do before IF_AFDATA_WLOCK to avoid deadlock */ - callout_halt(&la->la_timer, &la->lle_lock); - /* XXX: LOR avoidance. We still have ref on lle. */ - LLE_RUNLOCK(la); - - flags |= LLE_EXCLUSIVE; - IF_AFDATA_WLOCK(ifp); - LLE_WLOCK(la); - - if (la->la_rt != NULL) { - /* - * Don't rtfree (may actually free objects) here. - * Leave it to rtrequest1. - */ - la->la_rt->rt_refcnt--; - la->la_rt = NULL; - } - - /* Guard against race with other llentry_free(). */ - if (la->la_flags & LLE_LINKED) { - size_t pkts_dropped; - - pkts_dropped = llentry_free(la); - ARP_STATADD(ARP_STAT_DFRDROPPED, pkts_dropped); - } else { - LLE_FREE_LOCKED(la); - } - la = NULL; - - IF_AFDATA_WUNLOCK(ifp); - } - - if (la != NULL) { - if (flags & LLE_EXCLUSIVE) - LLE_WUNLOCK(la); - else - LLE_RUNLOCK(la); } } @@ -811,28 +696,19 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt, struct mbuf *m, const struct sockaddr *dst, u_char *desten) { struct llentry *la; - const struct sockaddr_dl *sdl; const char *create_lookup; bool renew; int error; KASSERT(m != NULL); - la = arplookup(ifp, m, &satocsin(dst)->sin_addr, 0, 0, 0, rt); - if (la == NULL || la->la_rt == NULL) + la = arplookup(ifp, m, NULL, dst, 0); + if (la == NULL) goto notfound; - rt = la->la_rt; - sdl = satocsdl(rt->rt_gateway); - /* - * Check the address family and length is valid, the address - * is resolved; otherwise, try to resolve. - */ - if ((rt->rt_expire == 0 || rt->rt_expire > time_uptime) && - sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) { - memcpy(desten, CLLADDR(sdl), - min(sdl->sdl_alen, ifp->if_addrlen)); - rt->rt_pksent = time_uptime; /* Time for last pkt sent */ + if ((la->la_flags & LLE_VALID) && + ((la->la_flags & LLE_STATIC) || la->la_expire > time_uptime)) { + memcpy(desten, &la->ll_addr, ifp->if_addrlen); LLE_RUNLOCK(la); return 0; } @@ -869,6 +745,8 @@ notfound: IF_AFDATA_WUNLOCK(ifp); if (la == NULL) ARP_STATINC(ARP_STAT_ALLOCFAIL); + else + arp_init_llentry(ifp, la); } else if (LLE_TRY_UPGRADE(la) == 0) { create_lookup = "lookup"; LLE_RUNLOCK(la); @@ -886,23 +764,10 @@ notfound: goto bad; } - /* Just in case */ - if (la->la_rt == NULL) { - LLE_WUNLOCK(la); - log(LOG_DEBUG, - "%s: valid llentry has no rtentry for %s on %s\n", - __func__, inet_ntoa(satocsin(dst)->sin_addr), - ifp->if_xname); - goto bad; - } - rt = la->la_rt; - if ((la->la_flags & LLE_VALID) && ((la->la_flags & LLE_STATIC) || la->la_expire > time_uptime)) { - sdl = satocsdl(rt->rt_gateway); - memcpy(desten, CLLADDR(sdl), - min(sdl->sdl_alen, ifp->if_addrlen)); + memcpy(desten, &la->ll_addr, ifp->if_addrlen); renew = false; /* * If entry has an expiry time and it is approaching, @@ -921,8 +786,8 @@ notfound: if (renew) { const u_int8_t *enaddr = #if NCARP > 0 - (rt->rt_ifp->if_type == IFT_CARP) ? - CLLADDR(rt->rt_ifp->if_sadl): + (ifp->if_type == IFT_CARP) ? + CLLADDR(ifp->if_sadl): #endif CLLADDR(ifp->if_sadl); arprequest(ifp, @@ -979,13 +844,13 @@ notfound: if (la->la_asked < arp_maxtries) error = EWOULDBLOCK; /* First request. */ else - error = (rt->rt_flags & RTF_GATEWAY) ? + error = (rt != NULL && rt->rt_flags & RTF_GATEWAY) ? EHOSTUNREACH : EHOSTDOWN; if (renew) { const u_int8_t *enaddr = #if NCARP > 0 - (rt->rt_ifp->if_type == IFT_CARP) ? + (rt != NULL && rt->rt_ifp->if_type == IFT_CARP) ? CLLADDR(rt->rt_ifp->if_sadl): #endif CLLADDR(ifp->if_sadl); @@ -994,8 +859,23 @@ notfound: la->la_asked++; LLE_WUNLOCK(la); - arprequest(ifp, &satocsin(rt->rt_ifa->ifa_addr)->sin_addr, - &satocsin(dst)->sin_addr, enaddr); + if (rt != NULL) { + arprequest(ifp, &satocsin(rt->rt_ifa->ifa_addr)->sin_addr, + &satocsin(dst)->sin_addr, enaddr); + } else { + struct sockaddr_in sin; + + sockaddr_in_init(&sin, &la->r_l3addr.addr4, 0); + + /* XXX */ + rt = rtalloc1((struct sockaddr *)&sin, 0); + if (rt == NULL) + goto bad; + arprequest(ifp, &satocsin(rt->rt_ifa->ifa_addr)->sin_addr, + &satocsin(dst)->sin_addr, enaddr); + rtfree(rt); + rt = NULL; + } return error; } @@ -1004,10 +884,6 @@ notfound: bad: m_freem(m); - if (rt != NULL && (rt->rt_flags & RTF_CLONED) != 0) { - rtrequest(RTM_DELETE, rt_getkey(rt), - rt->rt_gateway, rt_mask(rt), rt->rt_flags, NULL); - } return error; } @@ -1093,7 +969,6 @@ in_arpinput(struct mbuf *m) struct arphdr *ah; struct ifnet *ifp = m->m_pkthdr.rcvif; struct llentry *la = NULL; - struct rtentry *rt = NULL; struct in_ifaddr *ia; #if NBRIDGE > 0 struct in_ifaddr *bridge_ia = NULL; @@ -1101,7 +976,6 @@ in_arpinput(struct mbuf *m) #if NCARP > 0 u_int32_t count = 0, index = 0; #endif - struct sockaddr_dl *sdl = NULL; struct sockaddr sa; struct in_addr isaddr, itaddr, myaddr; int op; @@ -1257,17 +1131,16 @@ in_arpinput(struct mbuf *m) goto reply; } - la = arplookup(ifp, m, &isaddr, in_hosteq(itaddr, myaddr), 0, 1, NULL); - if (la != NULL) { - rt = la->la_rt; - if (rt != NULL) - sdl = satosdl(rt->rt_gateway); - } - if (sdl == NULL) + if (in_hosteq(itaddr, myaddr)) + la = arpcreate(ifp, m, &isaddr, NULL, 1); + else + la = arplookup(ifp, m, &isaddr, NULL, 1); + if (la == NULL) goto reply; - if (sdl->sdl_alen && memcmp(ar_sha(ah), CLLADDR(sdl), sdl->sdl_alen)) { - if (rt->rt_flags & RTF_STATIC) { + if ((la->la_flags & LLE_VALID) && + memcmp(ar_sha(ah), &la->ll_addr, ifp->if_addrlen)) { + if (la->la_flags & LLE_STATIC) { ARP_STATINC(ARP_STAT_RCVOVERPERM); if (!log_permanent_modify) goto out; @@ -1277,7 +1150,8 @@ in_arpinput(struct mbuf *m) lla_snprintf(ar_sha(ah), ah->ar_hln), in_fmtaddr(isaddr)); goto out; - } else if (rt->rt_ifp != ifp) { + } else if (la->lle_tbl->llt_ifp != ifp) { + /* XXX should not happen? */ ARP_STATINC(ARP_STAT_RCVOVERINT); if (!log_wrong_iface) goto out; @@ -1286,7 +1160,7 @@ in_arpinput(struct mbuf *m) "arp info for %s on %s\n", lla_snprintf(ar_sha(ah), ah->ar_hln), ifp->if_xname, in_fmtaddr(isaddr), - rt->rt_ifp->if_xname); + la->lle_tbl->llt_ifp->if_xname); goto out; } else { ARP_STATINC(ARP_STAT_RCVOVER); @@ -1299,6 +1173,8 @@ in_arpinput(struct mbuf *m) } } + /* XXX llentry should have addrlen? */ +#if 0 /* * sanity check for the address length. * XXX this does not work for protocols with variable address @@ -1310,6 +1186,8 @@ in_arpinput(struct mbuf *m) "arp from %s: new addr len %d, was %d\n", in_fmtaddr(isaddr), ah->ar_hln, sdl->sdl_alen); } +#endif + if (ifp->if_addrlen != ah->ar_hln) { ARP_STATINC(ARP_STAT_RCVBADLEN); log(LOG_WARNING, @@ -1346,19 +1224,21 @@ in_arpinput(struct mbuf *m) } } #endif /* NTOKEN > 0 */ - (void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, ar_sha(ah), ah->ar_hln); - if (rt->rt_expire) { - rt->rt_expire = time_uptime + arpt_keep; - KASSERT((la->la_flags & LLE_STATIC) == 0); - arp_settimer(la, arpt_keep); - } - rt->rt_flags &= ~RTF_REJECT; + (void)memcpy(&la->ll_addr, ar_sha(ah), ifp->if_addrlen); + la->la_flags |= LLE_VALID; + la->la_expire = time_uptime + arpt_keep; la->la_asked = 0; + KASSERT((la->la_flags & LLE_STATIC) == 0); + arp_settimer(la, arpt_keep); + /* rt->rt_flags &= ~RTF_REJECT; */ if (la->la_hold != NULL) { int n = la->la_numheld; struct mbuf *m_hold, *m_hold_next; + struct sockaddr_in sin; + + sockaddr_in_init(&sin, &la->r_l3addr.addr4, 0); m_hold = la->la_hold; la->la_hold = NULL; @@ -1372,7 +1252,7 @@ in_arpinput(struct mbuf *m) for (; m_hold != NULL; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; - (*ifp->if_output)(ifp, m_hold, rt_getkey(rt), rt); + (*ifp->if_output)(ifp, m_hold, sintosa(&sin), NULL); } } else LLE_WUNLOCK(la); @@ -1399,20 +1279,33 @@ reply: memcpy(tha, ar_sha(ah), ah->ar_hln); memcpy(ar_sha(ah), CLLADDR(ifp->if_sadl), ah->ar_hln); } else { - la = arplookup(ifp, m, &itaddr, 0, SIN_PROXY, 0, NULL); - if (la == NULL) - goto out; - rt = la->la_rt; - LLE_RUNLOCK(la); - la = NULL; - if (rt->rt_ifp->if_type == IFT_CARP && + /* Proxy ARP */ + struct llentry *lle = NULL; + struct sockaddr_in sin; + +#if NCARP > 0 + if (ifp->if_type == IFT_CARP && m->m_pkthdr.rcvif->if_type != IFT_CARP) goto out; +#endif + tha = ar_tha(ah); - if (tha) - memcpy(tha, ar_sha(ah), ah->ar_hln); - sdl = satosdl(rt->rt_gateway); - memcpy(ar_sha(ah), CLLADDR(sdl), ah->ar_hln); + + sockaddr_in_init(&sin, &itaddr, 0); + + IF_AFDATA_RLOCK(ifp); + lle = lla_lookup(LLTABLE(ifp), 0, (struct sockaddr *)&sin); + IF_AFDATA_RUNLOCK(ifp); + + if ((lle != NULL) && (lle->la_flags & LLE_PUB)) { + (void)memcpy(tha, ar_sha(ah), ah->ar_hln); + (void)memcpy(ar_sha(ah), &lle->ll_addr, ah->ar_hln); + LLE_RUNLOCK(lle); + } else { + if (lle != NULL) + LLE_RUNLOCK(lle); + goto drop; + } } memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln); @@ -1447,95 +1340,61 @@ reply: out: if (la != NULL) LLE_WUNLOCK(la); +drop: m_freem(m); } /* - * Free an arp entry. - */ -static void arptfree(struct rtentry *rt) -{ - - /* We still need to hold the locks */ - mutex_enter(softnet_lock); - KERNEL_LOCK(1, NULL); - - rtrequest(RTM_DELETE, rt_getkey(rt), NULL, rt_mask(rt), 0, NULL); - rtfree(rt); - - KERNEL_UNLOCK_ONE(NULL); - mutex_exit(softnet_lock); -} - -/* - * Lookup or enter a new address in arptab. + * Lookup or a new address in arptab. */ static struct llentry * arplookup(struct ifnet *ifp, struct mbuf *m, const struct in_addr *addr, - int create, int proxy, int wlock, struct rtentry *rt0) + const struct sockaddr *sa, int wlock) { - struct arphdr *ah; - struct rtentry *rt; - struct sockaddr_inarp sin; - const char *why = NULL; + struct sockaddr_in sin; + struct llentry *la; + int flags = wlock ? LLE_EXCLUSIVE : 0; - ah = mtod(m, struct arphdr *); - if (rt0 == NULL) { - memset(&sin, 0, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - sin.sin_addr = *addr; - sin.sin_other = proxy ? SIN_PROXY : 0; - rt = rtalloc1(sintosa(&sin), create); - if (rt == NULL) - return NULL; - rt->rt_refcnt--; - } else - rt = rt0; -#define IS_LLINFO(__rt) \ - (((__rt)->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) == RTF_LLINFO && \ - (__rt)->rt_gateway->sa_family == AF_LINK) + if (sa == NULL) { + KASSERT(addr != NULL); + sockaddr_in_init(&sin, addr, 0); + sa = sintocsa(&sin); + } + IF_AFDATA_RLOCK(ifp); + la = lla_lookup(LLTABLE(ifp), flags, sa); + IF_AFDATA_RUNLOCK(ifp); - if (IS_LLINFO(rt)) { - struct llentry *la; - int flags = wlock ? LLE_EXCLUSIVE : 0; + return la; +} - IF_AFDATA_RLOCK(ifp); - la = lla_lookup(LLTABLE(ifp), flags, rt_getkey(rt)); - IF_AFDATA_RUNLOCK(ifp); +static struct llentry * +arpcreate(struct ifnet *ifp, struct mbuf *m, const struct in_addr *addr, + const struct sockaddr *sa, int wlock) +{ + struct sockaddr_in sin; + struct llentry *la; + int flags = wlock ? LLE_EXCLUSIVE : 0; + + if (sa == NULL) { + KASSERT(addr != NULL); + sockaddr_in_init(&sin, addr, 0); + sa = sintocsa(&sin); + } - if (la == NULL && create) { - IF_AFDATA_WLOCK(ifp); - la = lla_create(LLTABLE(ifp), flags, rt_getkey(rt)); - IF_AFDATA_WUNLOCK(ifp); - } + la = arplookup(ifp, m, addr, sa, wlock); - return la; - } + if (la == NULL) { + IF_AFDATA_WLOCK(ifp); + la = lla_create(LLTABLE(ifp), flags, sa); + IF_AFDATA_WUNLOCK(ifp); - if (create) { - if (rt->rt_flags & RTF_GATEWAY) { - if (log_unknown_network) - why = "host is not on local network"; - } else if ((rt->rt_flags & RTF_LLINFO) == 0) { - ARP_STATINC(ARP_STAT_ALLOCFAIL); - why = "could not allocate llinfo"; - } else - why = "gateway route is not ours"; - if (why) { - log(LOG_DEBUG, "arplookup: unable to enter address" - " for %s@%s on %s (%s)\n", in_fmtaddr(*addr), - lla_snprintf(ar_sha(ah), ah->ar_hln), - (ifp) ? ifp->if_xname : "null", why); - } - if ((rt->rt_flags & RTF_CLONED) != 0) { - rtrequest(RTM_DELETE, rt_getkey(rt), - rt->rt_gateway, rt_mask(rt), rt->rt_flags, NULL); - } + if (la != NULL) + arp_init_llentry(ifp, la); } - return NULL; + + return la; } int @@ -1557,11 +1416,31 @@ arp_ifinit(struct ifnet *ifp, struct ifaddr *ifa) */ ip = &IA_SIN(ifa)->sin_addr; if (!in_nullhost(*ip) && - (ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED)) == 0) + (ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED)) == 0) { + struct llentry *lle; + arprequest(ifp, ip, ip, CLLADDR(ifp->if_sadl)); + /* + * interface address is considered static entry + * because the output of the arp utility shows + * that L2 entry as permanent + */ + IF_AFDATA_WLOCK(ifp); + lle = lla_create(LLTABLE(ifp), (LLE_IFADDR | LLE_STATIC), + (struct sockaddr *)IA_SIN(ifa)); + IF_AFDATA_WUNLOCK(ifp); + if (lle == NULL) + log(LOG_INFO, "arp_ifinit: cannot create arp " + "entry for interface address\n"); + else { + arp_init_llentry(ifp, lle); + LLE_RUNLOCK(lle); + } + } + ifa->ifa_rtrequest = arp_rtrequest; - ifa->ifa_flags |= RTF_CLONING; + ifa->ifa_flags |= RTF_CONNECTED; /* ARP will handle DAD for this address. */ if (ia->ia4_flags & IN_IFF_TRYTENTATIVE) { @@ -2093,8 +1972,7 @@ db_print_llinfo(struct llentry *la) { if (la == NULL) return; - db_printf(" la_rt=%p la_hold=%p, la_asked=%d\n", - la->la_rt, la->la_hold, la->la_asked); + db_printf(" la_hold=%p, la_asked=%d\n", la->la_hold, la->la_asked); db_printf(" la_flags=0x%x\n", la->la_flags); } diff --git a/sys/netinet/if_atm.c b/sys/netinet/if_atm.c index 51704ee..9c60887 100644 --- a/sys/netinet/if_atm.c +++ b/sys/netinet/if_atm.c @@ -120,10 +120,6 @@ atm_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) break; } - if ((rt->rt_flags & RTF_CLONING) != 0) { - printf("atm_rtrequest: cloning route detected?\n"); - break; - } if (gate->sa_family != AF_LINK || gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) { log(LOG_DEBUG, "atm_rtrequest: bad gateway value\n"); @@ -151,7 +147,6 @@ atm_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) npcb->ipaddr.s_addr = sin->sin_addr.s_addr; /* XXX: move npcb to llinfo when ATM ARP is ready */ rt->rt_llinfo = (void *) npcb; - rt->rt_flags |= RTF_LLINFO; #endif /* * let the lower level know this circuit is active @@ -173,7 +168,6 @@ failed: if (npcb) { npcb_free(npcb, NPCB_DESTROY); rt->rt_llinfo = NULL; - rt->rt_flags &= ~RTF_LLINFO; } #endif rtrequest(RTM_DELETE, rt_getkey(rt), NULL, @@ -182,18 +176,6 @@ failed: case RTM_DELETE: -#ifdef NATM - /* - * tell native ATM we are done with this VC - */ - - if (rt->rt_flags & RTF_LLINFO) { - npcb_free((struct natmpcb *)rt->rt_llinfo, - NPCB_DESTROY); - rt->rt_llinfo = NULL; - rt->rt_flags &= ~RTF_LLINFO; - } -#endif /* * tell the lower layer to disable this circuit */ @@ -239,7 +221,6 @@ atmresolve(struct rtentry *rt0, struct mbuf *m, const struct sockaddr *dst, if (rt == NULL) goto bad; /* failed */ if ((rt->rt_flags & RTF_GATEWAY) != 0 || - (rt->rt_flags & RTF_LLINFO) == 0 || /* XXX: are we using LLINFO? */ rt->rt_gateway->sa_family != AF_LINK) { rtfree(rt); diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 3499ae3..20bb898 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -1855,6 +1855,23 @@ in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3add return lle; } +static int +in_lltable_dump_entry(struct lltable *llt, struct llentry *lle, + struct rt_walkarg *w) +{ + struct sockaddr_in sin; + + LLTABLE_LOCK_ASSERT(); + + /* skip deleted entries */ + if (lle->la_flags & LLE_DELETED) + return 0; + + sockaddr_in_init(&sin, &lle->r_l3addr.addr4, 0); + + return lltable_dump_entry(llt, lle, w, sintosa(&sin)); +} + #endif /* NARP > 0 */ static void @@ -1904,9 +1921,7 @@ in_lltattach(struct ifnet *ifp) llt->llt_lookup = in_lltable_lookup; llt->llt_create = in_lltable_create; llt->llt_delete = in_lltable_delete; -#if 0 llt->llt_dump_entry = in_lltable_dump_entry; -#endif llt->llt_hash = in_lltable_hash; llt->llt_fill_sa_entry = in_lltable_fill_sa_entry; llt->llt_free_entry = in_lltable_free_entry; diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 96ff802..2dd506a 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -394,7 +394,7 @@ carp_setroute(struct carp_softc *sc, int cmd) (void)rtrequest(RTM_GET, ifa->ifa_addr, ifa->ifa_addr, ifa->ifa_netmask, RTF_HOST, &rt); hr_otherif = (rt && rt->rt_ifp != &sc->sc_if && - rt->rt_flags & (RTF_CLONING|RTF_CLONED)); + (rt->rt_flags & RTF_CONNECTED)); if (rt != NULL) { rtfree(rt); rt = NULL; @@ -411,22 +411,22 @@ carp_setroute(struct carp_softc *sc, int cmd) case RTM_ADD: if (hr_otherif) { ifa->ifa_rtrequest = NULL; - ifa->ifa_flags &= ~RTF_CLONING; + ifa->ifa_flags &= ~RTF_CONNECTED; rtrequest(RTM_ADD, ifa->ifa_addr, ifa->ifa_addr, ifa->ifa_netmask, RTF_UP | RTF_HOST, NULL); } if (!hr_otherif || nr_ourif || !rt) { - if (nr_ourif && !(rt->rt_flags & - RTF_CLONING)) + if (nr_ourif && + (rt->rt_flags & RTF_CONNECTED) == 0) rtrequest(RTM_DELETE, ifa->ifa_addr, ifa->ifa_addr, ifa->ifa_netmask, 0, NULL); ifa->ifa_rtrequest = arp_rtrequest; - ifa->ifa_flags |= RTF_CLONING; + ifa->ifa_flags |= RTF_CONNECTED; if (rtrequest(RTM_ADD, ifa->ifa_addr, ifa->ifa_addr, ifa->ifa_netmask, 0, diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 8ff81f0..4895dbc 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -2462,35 +2462,30 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt) { /* target lladdr option */ - struct rtentry *rt_nexthop = NULL; + struct llentry *ln = NULL; int len; - const struct sockaddr_dl *sdl; struct nd_opt_hdr *nd_opt; char *lladdr; - rt_nexthop = nd6_lookup(nexthop, 0, ifp); - if (!rt_nexthop) + ln = nd6_lookup(nexthop, ifp, false); + if (ln == NULL) goto nolladdropt; len = sizeof(*nd_opt) + ifp->if_addrlen; len = (len + 7) & ~7; /* round by 8 */ /* safety check */ if (len + (p - (u_char *)ip6) > maxlen) { - rtfree(rt_nexthop); + LLE_RUNLOCK(ln); goto nolladdropt; } - if (!(rt_nexthop->rt_flags & RTF_GATEWAY) && - (rt_nexthop->rt_flags & RTF_LLINFO) && - (rt_nexthop->rt_gateway->sa_family == AF_LINK) && - (sdl = satocsdl(rt_nexthop->rt_gateway)) && - sdl->sdl_alen) { + if (ln->la_flags & LLE_VALID) { nd_opt = (struct nd_opt_hdr *)p; nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; nd_opt->nd_opt_len = len >> 3; lladdr = (char *)(nd_opt + 1); - memcpy(lladdr, CLLADDR(sdl), ifp->if_addrlen); + memcpy(lladdr, &ln->ll_addr, ifp->if_addrlen); p += len; } - rtfree(rt_nexthop); + LLE_RUNLOCK(ln); } nolladdropt:; diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 4c8f44c..77243ed 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -1124,8 +1124,8 @@ in6_update_ifa1(struct ifnet *ifp, struct in6_aliasreq *ifra, (struct sockaddr *)&mltmask; info.rti_info[RTAX_IFA] = (struct sockaddr *)&ia->ia_addr; - /* XXX: we need RTF_CLONING to fake nd6_rtrequest */ - info.rti_flags = RTF_UP | RTF_CLONING; + /* XXX: we need RTF_CONNECTED to fake nd6_rtrequest */ + info.rti_flags = RTF_UP | RTF_CONNECTED; error = rtrequest1(RTM_ADD, &info, NULL); if (error) goto cleanup; @@ -1209,7 +1209,7 @@ in6_update_ifa1(struct ifnet *ifp, struct in6_aliasreq *ifra, (struct sockaddr *)&mltmask; info.rti_info[RTAX_IFA] = (struct sockaddr *)&ia->ia_addr; - info.rti_flags = RTF_UP | RTF_CLONING; + info.rti_flags = RTF_UP | RTF_CONNECTED; error = rtrequest1(RTM_ADD, &info, NULL); if (error) goto cleanup; @@ -1229,6 +1229,11 @@ in6_update_ifa1(struct ifnet *ifp, struct in6_aliasreq *ifra, } } + /* Add local address to lltable, if necessary (ex. on p2p link). */ + error = nd6_add_ifa_lle(ia); + if (error != 0) + goto cleanup; + /* * Perform DAD, if needed. * XXX It may be of use, if we can administratively @@ -2459,7 +2464,7 @@ in6_lltable_create(struct lltable *llt, u_int flags, lle->la_flags = flags; if ((flags & LLE_IFADDR) == LLE_IFADDR) { memcpy(&lle->ll_addr, CLLADDR(ifp->if_sadl), ifp->if_addrlen); - lle->la_flags |= (LLE_VALID | LLE_STATIC); + lle->la_flags |= LLE_VALID; } lltable_link_entry(llt, lle); @@ -2491,6 +2496,23 @@ in6_lltable_lookup(struct lltable *llt, u_int flags, return lle; } +static int +in6_lltable_dump_entry(struct lltable *llt, struct llentry *lle, + struct rt_walkarg *w) +{ + struct sockaddr_in6 sin6; + + LLTABLE_LOCK_ASSERT(); + + /* skip deleted entries */ + if (lle->la_flags & LLE_DELETED) + return 0; + + sockaddr_in6_init(&sin6, &lle->r_l3addr.addr6, 0, 0, 0); + + return lltable_dump_entry(llt, lle, w, sin6tosa(&sin6)); +} + static struct lltable * in6_lltattach(struct ifnet *ifp) { @@ -2503,9 +2525,7 @@ in6_lltattach(struct ifnet *ifp) llt->llt_lookup = in6_lltable_lookup; llt->llt_create = in6_lltable_create; llt->llt_delete = in6_lltable_delete; -#if notyet llt->llt_dump_entry = in6_lltable_dump_entry; -#endif llt->llt_hash = in6_lltable_hash; llt->llt_fill_sa_entry = in6_lltable_fill_sa_entry; llt->llt_free_entry = in6_lltable_free_entry; diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 139f9a0..97fd105 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -480,7 +480,6 @@ ip6_input(struct mbuf *m) */ if (rt != NULL && (rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST && - !(rt->rt_flags & RTF_CLONED) && #if 0 /* * The check below is redundant since the comparison of diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 2eeb9e1..2891d5a 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -102,9 +102,6 @@ int nd6_debug = 1; int nd6_debug = 0; #endif -/* for debugging? */ -static int nd6_inuse, nd6_allocated; - struct nd_drhead nd_defrouter; struct nd_prhead nd_prefix = { 0 }; @@ -121,7 +118,7 @@ static const struct sockaddr_in6 all1_sa = { static void nd6_setmtu0(struct ifnet *, struct nd_ifinfo *); static void nd6_slowtimo(void *); static int regen_tmpaddr(struct in6_ifaddr *); -static void nd6_free(struct rtentry *, struct llentry *, int); +static void nd6_free(struct llentry *, int); static void nd6_llinfo_timer(void *); static void clear_llinfo_pqueue(struct llentry *); @@ -390,7 +387,7 @@ skip1: * ND6 timer routine to handle ND6 entries */ void -nd6_llinfo_settimer_locked(struct llentry *ln, time_t xtick) +nd6_llinfo_settimer(struct llentry *ln, time_t xtick) { CTASSERT(sizeof(time_t) > sizeof(int)); @@ -415,15 +412,6 @@ nd6_llinfo_settimer_locked(struct llentry *ln, time_t xtick) } } -void -nd6_llinfo_settimer(struct llentry *ln, time_t xtick) -{ - - LLE_WLOCK(ln); - nd6_llinfo_settimer_locked(ln, xtick); - LLE_WUNLOCK(ln); -} - /* * Gets source address of the first packet in hold queue * and stores it in @src. @@ -454,8 +442,6 @@ static void nd6_llinfo_timer(void *arg) { struct llentry *ln = arg; - struct rtentry *rt; - const struct sockaddr_in6 *dst; struct ifnet *ifp; struct nd_ifinfo *ndi = NULL; bool send_ns = false; @@ -466,7 +452,7 @@ nd6_llinfo_timer(void *arg) LLE_WLOCK(ln); if (ln->ln_ntick > 0) { - nd6_llinfo_settimer_locked(ln, ln->ln_ntick); + nd6_llinfo_settimer(ln, ln->ln_ntick); goto out; } @@ -484,27 +470,17 @@ nd6_llinfo_timer(void *arg) * was restarted, the pending bit will be back on and * we just want to bail since the callout_reset would * return 1 and our reference would have been removed - * by nd6_llinfo_settimer_locked above since canceled + * by nd6_llinfo_settimer above since canceled * would have been 1. */ goto out; } ifp = ln->lle_tbl->llt_ifp; - rt = ln->ln_rt; - KASSERT(rt != NULL); KASSERT(ifp != NULL); ndi = ND_IFINFO(ifp); - dst = satocsin6(rt_getkey(rt)); - - /* sanity check */ - if (rt->rt_llinfo && (struct llentry *)rt->rt_llinfo != ln) - panic("rt_llinfo(%p) is not equal to ln(%p)", - rt->rt_llinfo, ln); - if (!dst) - panic("dst=0 in nd6_timer(ln=%p)", ln); switch (ln->ln_state) { case ND6_LLINFO_INCOMPLETE: @@ -525,7 +501,7 @@ nd6_llinfo_timer(void *arg) ln->ln_hold = m0; clear_llinfo_pqueue(ln); } - nd6_free(rt, ln, 0); + nd6_free(ln, 0); ln = NULL; if (m != NULL) icmp6_error2(m, ICMP6_DST_UNREACH, @@ -535,7 +511,7 @@ nd6_llinfo_timer(void *arg) case ND6_LLINFO_REACHABLE: if (!ND6_LLINFO_PERMANENT(ln)) { ln->ln_state = ND6_LLINFO_STALE; - nd6_llinfo_settimer_locked(ln, nd6_gctimer * hz); + nd6_llinfo_settimer(ln, nd6_gctimer * hz); } break; @@ -543,7 +519,7 @@ nd6_llinfo_timer(void *arg) case ND6_LLINFO_STALE: /* Garbage Collection(RFC 2461 5.3) */ if (!ND6_LLINFO_PERMANENT(ln)) { - nd6_free(rt, ln, 1); + nd6_free(ln, 1); ln = NULL; } break; @@ -553,20 +529,20 @@ nd6_llinfo_timer(void *arg) /* We need NUD */ ln->ln_asked = 1; ln->ln_state = ND6_LLINFO_PROBE; - daddr6 = &dst->sin6_addr; + daddr6 = &ln->r_l3addr.addr6; send_ns = true; } else { ln->ln_state = ND6_LLINFO_STALE; /* XXX */ - nd6_llinfo_settimer_locked(ln, nd6_gctimer * hz); + nd6_llinfo_settimer(ln, nd6_gctimer * hz); } break; case ND6_LLINFO_PROBE: if (ln->ln_asked < nd6_umaxtries) { ln->ln_asked++; - daddr6 = &dst->sin6_addr; + daddr6 = &ln->r_l3addr.addr6; send_ns = true; } else { - nd6_free(rt, ln, 0); + nd6_free(ln, 0); ln = NULL; } break; @@ -574,12 +550,13 @@ nd6_llinfo_timer(void *arg) if (send_ns) { struct in6_addr src, *psrc; + const struct in6_addr *taddr6 = &ln->r_l3addr.addr6; - nd6_llinfo_settimer_locked(ln, ndi->retrans * hz / 1000); + nd6_llinfo_settimer(ln, ndi->retrans * hz / 1000); psrc = nd6_llinfo_get_holdsrc(ln, &src); LLE_FREE_LOCKED(ln); ln = NULL; - nd6_ns_output(ifp, daddr6, &dst->sin6_addr, psrc, 0); + nd6_ns_output(ifp, daddr6, taddr6, psrc, 0); } out: @@ -889,127 +866,142 @@ nd6_purge(struct ifnet *ifp, struct in6_ifextra *ext) lltable_purge_entries(ext->lltable); } -static struct rtentry * -nd6_lookup1(const struct in6_addr *addr6, int create, struct ifnet *ifp, - int cloning) +struct llentry * +nd6_lookup(const struct in6_addr *addr6, const struct ifnet *ifp, bool wlock) { - struct rtentry *rt; struct sockaddr_in6 sin6; + struct llentry *ln; sockaddr_in6_init(&sin6, addr6, 0, 0, 0); - rt = rtalloc1((struct sockaddr *)&sin6, create); - if (rt != NULL && (rt->rt_flags & RTF_LLINFO) == 0) { + + IF_AFDATA_RLOCK(ifp); + ln = lla_lookup(LLTABLE6(ifp), wlock ? LLE_EXCLUSIVE : 0, + sin6tosa(&sin6)); + IF_AFDATA_RUNLOCK(ifp); + + return ln; +} + +struct llentry * +nd6_create(const struct in6_addr *addr6, const struct ifnet *ifp) +{ + struct sockaddr_in6 sin6; + struct llentry *ln; + + sockaddr_in6_init(&sin6, addr6, 0, 0, 0); + + IF_AFDATA_WLOCK(ifp); + ln = lla_create(LLTABLE6(ifp), LLE_EXCLUSIVE, + sin6tosa(&sin6)); + IF_AFDATA_WUNLOCK(ifp); + + if (ln != NULL) + ln->ln_state = ND6_LLINFO_NOSTATE; + + return ln; +} + +/* + * Test whether a given IPv6 address is a neighbor or not, ignoring + * the actual neighbor cache. The neighbor cache is ignored in order + * to not reenter the routing code from within itself. + */ +static int +nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) +{ + struct nd_prefix *pr; + struct ifaddr *dstaddr; + + /* + * A link-local address is always a neighbor. + * XXX: a link does not necessarily specify a single interface. + */ + if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { + struct sockaddr_in6 sin6_copy; + u_int32_t zone; + /* - * This is the case for the default route. - * If we want to create a neighbor cache for the address, we - * should free the route for the destination and allocate an - * interface route. + * We need sin6_copy since sa6_recoverscope() may modify the + * content (XXX). */ - if (create) { - rtfree(rt); - rt = NULL; - } + sin6_copy = *addr; + if (sa6_recoverscope(&sin6_copy)) + return 0; /* XXX: should be impossible */ + if (in6_setscope(&sin6_copy.sin6_addr, ifp, &zone)) + return 0; + if (sin6_copy.sin6_scope_id == zone) + return 1; + else + return 0; } - if (rt != NULL) - ; - else if (create && ifp) { - int e; - /* - * If no route is available and create is set, - * we allocate a host route for the destination - * and treat it like an interface route. - * This hack is necessary for a neighbor which can't - * be covered by our own prefix. - */ - struct ifaddr *ifa = - ifaof_ifpforaddr((struct sockaddr *)&sin6, ifp); - if (ifa == NULL) - return NULL; + /* + * 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. + */ + LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { + if (pr->ndpr_ifp != ifp) + continue; - /* - * Create a new route. RTF_LLINFO is necessary - * to create a Neighbor Cache entry for the - * destination in nd6_rtrequest which will be - * called in rtrequest via ifa->ifa_rtrequest. - */ - if ((e = rtrequest(RTM_ADD, (const struct sockaddr *)&sin6, - ifa->ifa_addr, (const struct sockaddr *)&all1_sa, - (ifa->ifa_flags | RTF_HOST | RTF_LLINFO) & - ~RTF_CLONING, &rt)) != 0) { -#if 0 - log(LOG_ERR, - "nd6_lookup: failed to add route for a " - "neighbor(%s), errno=%d\n", - ip6_sprintf(addr6), e); -#endif - return NULL; - } - if (rt == NULL) - return NULL; - if (rt->rt_llinfo) { - struct llentry *ln = rt->rt_llinfo; - ln->ln_state = ND6_LLINFO_NOSTATE; + if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) { + struct rtentry *rt; + + rt = rtalloc1((struct sockaddr *)&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)) { + continue; + } } - } else - return NULL; + + if (IN6_ARE_MASKED_ADDR_EQUAL(&pr->ndpr_prefix.sin6_addr, + &addr->sin6_addr, &pr->ndpr_mask)) + return 1; + } /* - * Check for a cloning route to match the address. - * This should only be set from in6_is_addr_neighbor so we avoid - * a potentially expensive second call to rtalloc1. + * If the address is assigned on the node of the other side of + * a p2p interface, the address should be a neighbor. */ - if (cloning && - rt->rt_flags & (RTF_CLONING | RTF_CLONED) && - (rt->rt_ifp == ifp -#if NBRIDGE > 0 - || rt->rt_ifp->if_bridge == ifp->if_bridge + dstaddr = ifa_ifwithdstaddr((const struct sockaddr *)addr); + if (dstaddr != NULL) { + if (dstaddr->ifa_ifp == ifp) { +#ifdef __FreeBSD__ + /* XXX we need to ifaref in ifa_ifwithdstaddr as well */ + ifafree(dstaddr); #endif -#if NCARP > 0 - || (ifp->if_type == IFT_CARP && rt->rt_ifp == ifp->if_carpdev) || - (rt->rt_ifp->if_type == IFT_CARP && rt->rt_ifp->if_carpdev == ifp)|| - (ifp->if_type == IFT_CARP && rt->rt_ifp->if_type == IFT_CARP && - rt->rt_ifp->if_carpdev == ifp->if_carpdev) + return 1; + } +#ifdef __FreeBSD__ + /* XXX we need to ifaref in ifa_ifwithdstaddr as well */ + ifafree(dstaddr); #endif - )) - return rt; + } /* - * Validation for the entry. - * Note that the check for rt_llinfo is necessary because a cloned - * route from a parent route that has the L flag (e.g. the default - * route to a p2p interface) may have the flag, too, while the - * destination is not actually a neighbor. - * XXX: we can't use rt->rt_ifp to check for the interface, since - * it might be the loopback interface if the entry is for our - * own address on a non-loopback interface. Instead, we should - * use rt->rt_ifa->ifa_ifp, which would specify the REAL - * interface. - * Note also that ifa_ifp and ifp may differ when we connect two - * interfaces to a same link, install a link prefix to an interface, - * and try to install a neighbor cache on an interface that does not - * have a route to the prefix. + * If the default router list is empty, all addresses are regarded + * as on-link, and thus, as a neighbor. */ - if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || - rt->rt_gateway->sa_family != AF_LINK || rt->rt_llinfo == NULL || - (ifp && rt->rt_ifa->ifa_ifp != ifp)) { - if (create) { - nd6log((LOG_DEBUG, - "nd6_lookup: failed to lookup %s (if = %s)\n", - ip6_sprintf(addr6), - ifp ? if_name(ifp) : "unspec")); - } - rtfree(rt); - return NULL; + if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && + TAILQ_EMPTY(&nd_defrouter) && + nd6_defifindex == ifp->if_index) { + return 1; } - return rt; -} - -struct rtentry * -nd6_lookup(const struct in6_addr *addr6, int create, struct ifnet *ifp) -{ - return nd6_lookup1(addr6, create, ifp, 0); + return 0; } /* @@ -1020,7 +1012,7 @@ int nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) { struct nd_prefix *pr; - struct rtentry *rt; + struct llentry *ln; /* * A link-local address is always a neighbor. @@ -1072,13 +1064,17 @@ nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) return 1; } + IF_AFDATA_UNLOCK_ASSERT(ifp); + if (nd6_is_new_addr_neighbor(addr, ifp)) + return 1; + /* * Even if the address matches none of our addresses, it might match * a cloning route or be in the neighbor cache. */ - rt = nd6_lookup1(&addr->sin6_addr, 0, ifp, 1); - if (rt != NULL) { - rtfree(rt); + ln = nd6_lookup(&addr->sin6_addr, ifp, false); + if (ln != NULL) { + LLE_RUNLOCK(ln); return 1; } @@ -1092,29 +1088,29 @@ nd6_is_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp) * that the change is safe. */ static void -nd6_free(struct rtentry *rt, struct llentry *ln, int gc) +nd6_free(struct llentry *ln, int gc) { - struct in6_addr in6 = satocsin6(rt_getkey(rt))->sin6_addr; struct nd_defrouter *dr; - int error; + struct ifnet *ifp; + struct in6_addr *in6; KASSERT(ln != NULL); - KASSERT(ln == rt->rt_llinfo); 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. */ /* cancel timer */ - nd6_llinfo_settimer_locked(ln, -1); + nd6_llinfo_settimer(ln, -1); if (!ip6_forwarding) { int s; s = splsoftnet(); - dr = defrouter_lookup(&satocsin6(rt_getkey(rt))->sin6_addr, - rt->rt_ifp); + dr = defrouter_lookup(in6, ifp); if (dr != NULL && dr->expire && ln->ln_state == ND6_LLINFO_STALE && gc) { @@ -1131,11 +1127,10 @@ nd6_free(struct rtentry *rt, struct llentry *ln, int gc) * but we intentionally keep it just in case. */ if (dr->expire > time_uptime) - nd6_llinfo_settimer_locked(ln, + nd6_llinfo_settimer(ln, (dr->expire - time_uptime) * hz); else - nd6_llinfo_settimer_locked(ln, - nd6_gctimer * hz); + nd6_llinfo_settimer(ln, nd6_gctimer * hz); splx(s); LLE_WUNLOCK(ln); return; @@ -1147,7 +1142,7 @@ nd6_free(struct rtentry *rt, struct llentry *ln, int gc) * is in the Default Router List. * See a corresponding comment in nd6_na_input(). */ - rt6_flush(&in6, rt->rt_ifp); + rt6_flush(in6, ifp); } if (dr) { @@ -1182,17 +1177,22 @@ nd6_free(struct rtentry *rt, struct llentry *ln, int gc) splx(s); } - LLE_WUNLOCK(ln); /* - * Detach the route from the routing tree and the list of neighbor - * caches, and disable the route entry not to be used in already - * cached routes. + * Save to unlock. We still hold an extra reference and will not + * free(9) in llentry_free() if someone else holds one as well. */ - error = rtrequest_newmsg(RTM_DELETE, rt_getkey(rt), NULL, - rt_mask(rt), 0); - if (error != 0) { - /* XXX need error message? */; - } + LLE_WUNLOCK(ln); + IF_AFDATA_LOCK(ifp); + LLE_WLOCK(ln); + + /* Guard against race with other llentry_free(). */ + if (ln->la_flags & LLE_LINKED) { + LLE_REMREF(ln); + llentry_free(ln); + } else + LLE_FREE_LOCKED(ln); + + IF_AFDATA_UNLOCK(ifp); } /* @@ -1204,21 +1204,18 @@ void nd6_nud_hint(struct rtentry *rt) { struct llentry *ln; + struct ifnet *ifp; if (rt == NULL) return; - if ((rt->rt_flags & RTF_GATEWAY) != 0 || - (rt->rt_flags & RTF_LLINFO) == 0 || - !rt->rt_llinfo || !rt->rt_gateway || - rt->rt_gateway->sa_family != AF_LINK) { - /* This is not a host route. */ + ifp = rt->rt_ifp; + ln = nd6_lookup(&(satocsin6(rt_getkey(rt)))->sin6_addr, ifp, true); + if (ln == NULL) return; - } - ln = rt->rt_llinfo; if (ln->ln_state < ND6_LLINFO_REACHABLE) - return; + goto done; /* * if we get upper-layer reachability confirmation many times, @@ -1226,13 +1223,14 @@ nd6_nud_hint(struct rtentry *rt) */ ln->ln_byhint++; if (ln->ln_byhint > nd6_maxnudhint) - return; + goto done; ln->ln_state = ND6_LLINFO_REACHABLE; - if (!ND6_LLINFO_PERMANENT(ln)) { - nd6_llinfo_settimer(ln, - ND_IFINFO(rt->rt_ifp)->reachable * hz); - } + if (!ND6_LLINFO_PERMANENT(ln)) + nd6_llinfo_settimer(ln, ND_IFINFO(rt->rt_ifp)->reachable * hz); + +done: + LLE_WUNLOCK(ln); return; } @@ -1253,7 +1251,7 @@ nd6_purge_entry(struct lltable *llt, struct llentry *ln, void *farg) ln->ln_state = ND6_LLINFO_STALE; else ln->ln_state = ND6_LLINFO_PURGE; - nd6_llinfo_settimer_locked(ln, 0); + nd6_llinfo_settimer(ln, 0); LLE_WUNLOCK(ln); (*n)--; @@ -1279,12 +1277,9 @@ void nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) { struct sockaddr *gate = rt->rt_gateway; - struct llentry *ln; struct ifnet *ifp = rt->rt_ifp; uint8_t namelen = strlen(ifp->if_xname), addrlen = ifp->if_addrlen; struct ifaddr *ifa; - int flags = 0; - bool use_lo0ifp = false; RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); @@ -1332,32 +1327,6 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) return; } - IF_AFDATA_RLOCK(ifp); - ln = lla_lookup(LLTABLE6(ifp), flags, rt_getkey(rt)); - IF_AFDATA_RUNLOCK(ifp); - - if (req == RTM_RESOLVE && - (nd6_need_cache(ifp) == 0 || /* stf case */ - !nd6_is_addr_neighbor(satocsin6(rt_getkey(rt)), ifp))) { - RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); - /* - * FreeBSD and BSD/OS often make a cloned host route based - * on a less-specific route (e.g. the default route). - * If the less specific route does not have a "gateway" - * (this is the case when the route just goes to a p2p or an - * stf interface), we'll mistakenly make a neighbor cache for - * the host route, and will see strange neighbor solicitation - * for the corresponding destination. In order to avoid the - * confusion, we check if the destination of the route is - * a neighbor in terms of neighbor discovery, and stop the - * process if not. Additionally, we remove the LLINFO flag - * so that ndp(8) will not try to get the neighbor information - * of the destination. - */ - rt->rt_flags &= ~RTF_LLINFO; - return; - } - switch (req) { case RTM_ADD: RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); @@ -1368,8 +1337,8 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) * SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff) * rt->rt_flags |= RTF_CLONING; */ - if ((rt->rt_flags & RTF_CLONING) || - ((rt->rt_flags & (RTF_LLINFO | RTF_LOCAL)) && ln == NULL)) { + /* XXX should move to route.c? */ + if (rt->rt_flags & (RTF_CONNECTED | RTF_LOCAL)) { union { struct sockaddr sa; struct sockaddr_dl sdl; @@ -1391,10 +1360,9 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) rt_setgate(rt, &u.sa); gate = rt->rt_gateway; RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); - if (ln != NULL) - nd6_llinfo_settimer_locked(ln, 0); + RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); - if ((rt->rt_flags & RTF_CLONING) != 0) + if ((rt->rt_flags & RTF_CONNECTED) != 0) break; } RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); @@ -1425,8 +1393,7 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) ip6_forwarding ? ND_NA_FLAG_ROUTER : 0, 1, NULL); #endif - /* FALLTHROUGH */ - case RTM_RESOLVE: + if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) { RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); /* @@ -1445,96 +1412,15 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) satosdl(gate)->sdl_index = ifp->if_index; RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); } - if (ln != NULL) - break; /* This happens on a route change */ - RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); - - /* Determine to use lo0ifp or not before lla_create */ - ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, - &satocsin6(rt_getkey(rt))->sin6_addr); - RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); - if (ifa != NULL && nd6_useloopback) - use_lo0ifp = true; - - /* - * Case 2: This route may come from cloning, or a manual route - * add with a LL address. - */ - flags = LLE_EXCLUSIVE; - if ((rt->rt_flags & RTF_CLONED) == 0) - flags |= LLE_IFADDR; - -#define _IFP() (use_lo0ifp ? lo0ifp : ifp) - IF_AFDATA_WLOCK(_IFP()); - ln = lla_create(LLTABLE6(_IFP()), flags, rt_getkey(rt)); - IF_AFDATA_WUNLOCK(_IFP()); - - RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); - if (ln == NULL) { - log(LOG_DEBUG, "nd6_rtrequest: malloc failed\n"); - break; - } - - RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); - nd6_inuse++; - nd6_allocated++; - ln->ln_rt = rt; - rt->rt_refcnt++; - rt->rt_llinfo = ln; - LLE_ADDREF(ln); - rt->rt_flags |= RTF_LLINFO; - switch (_IFP()->if_type) { -#if NTOKEN > 0 - case IFT_ISO88025: - ln->la_opaque = kmem_alloc(sizeof(struct token_rif), - KM_SLEEP); - break; -#endif /* NTOKEN > 0 */ - default: - break; - } -#undef _IFP - - /* this is required for "ndp" command. - shin */ - if (req == RTM_ADD) { - /* - * gate should have some valid AF_LINK entry, - * and ln->ln_expire should have some lifetime - * which is specified by ndp command. - */ - ln->ln_state = ND6_LLINFO_REACHABLE; - ln->ln_byhint = 0; - } else { - /* - * When req == RTM_RESOLVE, rt is created and - * initialized in rtrequest(), so rt_expire is 0. - */ - ln->ln_state = ND6_LLINFO_NOSTATE; - nd6_llinfo_settimer_locked(ln, 0); - } RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt)); /* * check if rt_getkey(rt) is an address assigned * to the interface. */ + ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, + &satocsin6(rt_getkey(rt))->sin6_addr); if (ifa != NULL) { - const void *mac; - nd6_llinfo_settimer_locked(ln, -1); - ln->ln_state = ND6_LLINFO_REACHABLE; - ln->ln_byhint = 0; - if ((mac = nd6_ifptomac(ifp)) != NULL) { - /* XXX check for error */ - if (sockaddr_dl_setaddr(satosdl(gate), - gate->sa_len, mac, - ifp->if_addrlen) == NULL) { - printf("%s.%d: " - "sockaddr_dl_setaddr(, %d, ) " - "failed on %s\n", __func__, - __LINE__, gate->sa_len, - if_name(ifp)); - } - } if (nd6_useloopback) { ifp = rt->rt_ifp = lo0ifp; /* XXX */ /* @@ -1547,15 +1433,8 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) */ if (ifa != rt->rt_ifa) rt_replace_ifa(rt, ifa); - rt->rt_rmx.rmx_mtu = 0; - rt->rt_flags &= ~RTF_CLONED; } - rt->rt_flags |= RTF_LOCAL; } else if (rt->rt_flags & RTF_ANNOUNCE) { - nd6_llinfo_settimer_locked(ln, -1); - ln->ln_state = ND6_LLINFO_REACHABLE; - ln->ln_byhint = 0; - /* join solicited node multicast for proxy ND */ if (ifp->if_flags & IFF_MULTICAST) { struct in6_addr llsol; @@ -1567,7 +1446,7 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) llsol.s6_addr32[2] = htonl(1); llsol.s6_addr8[12] = 0xff; if (in6_setscope(&llsol, ifp, NULL)) - break; + goto out; if (!in6_addmulti(&llsol, ifp, &error, 0)) { nd6log((LOG_ERR, "%s: failed to join " "%s (errno=%d)\n", if_name(ifp), @@ -1575,19 +1454,17 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) } } } - LLE_WUNLOCK(ln); + + out: /* * If we have too many cache entries, initiate immediate * purging for some entries. */ - nd6_gc_neighbors(ln->lle_tbl); - ln = NULL; - + if (rt->rt_ifp != NULL) + nd6_gc_neighbors(LLTABLE6(rt->rt_ifp)); break; case RTM_DELETE: - if (ln == NULL) - break; /* leave from solicited node multicast for proxy ND */ if ((rt->rt_flags & RTF_ANNOUNCE) != 0 && (ifp->if_flags & IFF_MULTICAST) != 0) { @@ -1605,57 +1482,7 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) in6_delmulti(in6m); } } - nd6_inuse--; - rt->rt_llinfo = NULL; - rt->rt_flags &= ~RTF_LLINFO; - - /* Have to do before IF_AFDATA_WLOCK to avoid deadlock */ - callout_halt(&ln->la_timer, &ln->lle_lock); - /* XXX: LOR avoidance. We still have ref on lle. */ - LLE_RUNLOCK(ln); - - IF_AFDATA_WLOCK(ifp); - LLE_WLOCK(ln); - - clear_llinfo_pqueue(ln); - if (ln->la_opaque != NULL) { - switch (ifp->if_type) { -#if NTOKEN > 0 - case IFT_ISO88025: - kmem_free(ln->la_opaque, - sizeof(struct token_rif)); - break; -#endif /* NTOKEN > 0 */ - default: - break; - } - } - - if (ln->la_rt != NULL) { - /* - * Don't rtfree (may actually free objects) here. - * Leave it to rtrequest1. - */ - ln->la_rt->rt_refcnt--; - ln->la_rt = NULL; - } - /* Guard against race with other llentry_free(). */ - if (ln->la_flags & LLE_LINKED) { - LLE_REMREF(ln); - llentry_free(ln); - } else { - LLE_FREE_LOCKED(ln); - } - - IF_AFDATA_WUNLOCK(ifp); - ln = NULL; - } - - if (ln != NULL) { - if (flags & LLE_EXCLUSIVE) - LLE_WUNLOCK(ln); - else - LLE_RUNLOCK(ln); + break; } } @@ -1941,24 +1768,13 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) { struct llentry *ln; struct in6_addr nb_addr = nbi->addr; /* make local for safety */ - struct rtentry *rt; if ((error = in6_setscope(&nb_addr, ifp, NULL)) != 0) return error; - s = splsoftnet(); - rt = nd6_lookup(&nb_addr, 0, ifp); - if (rt == NULL) { - error = EINVAL; - splx(s); - break; - } - - ln = rt->rt_llinfo; - rtfree(rt); + ln = nd6_lookup(&nb_addr, ifp, false); if (ln == NULL) { error = EINVAL; - splx(s); break; } nbi->state = ln->ln_state; @@ -1966,7 +1782,7 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) nbi->isrouter = ln->ln_router; nbi->expire = ln->ln_expire ? time_mono_to_wall(ln->ln_expire) : 0; - splx(s); + LLE_RUNLOCK(ln); break; } @@ -1980,14 +1796,19 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp) } void -nd6_llinfo_release_pkts(struct llentry *ln, struct ifnet *ifp, - struct rtentry *rt) +nd6_llinfo_release_pkts(struct llentry *ln, struct ifnet *ifp) { struct mbuf *m_hold, *m_hold_next; + struct sockaddr_in6 sin6; - for (m_hold = ln->la_hold, ln->la_hold = NULL, ln->la_numheld = 0; - m_hold != NULL; - m_hold = m_hold_next) { + LLE_WLOCK_ASSERT(ln); + + sockaddr_in6_init(&sin6, &ln->r_l3addr.addr6, 0, 0, 0); + + m_hold = ln->la_hold, ln->la_hold = NULL, ln->la_numheld = 0; + + LLE_WUNLOCK(ln); + for (; m_hold != NULL; m_hold = m_hold_next) { m_hold_next = m_hold->m_nextpkt; m_hold->m_nextpkt = NULL; @@ -1996,8 +1817,9 @@ nd6_llinfo_release_pkts(struct llentry *ln, struct ifnet *ifp, * just set the 2nd argument as the * 1st one. */ - nd6_output(ifp, ifp, m_hold, satocsin6(rt_getkey(rt)), rt); + nd6_output(ifp, ifp, m_hold, &sin6, NULL); } + LLE_WLOCK(ln); } /* @@ -2015,14 +1837,13 @@ nd6_cache_lladdr( ) { struct nd_ifinfo *ndi = ND_IFINFO(ifp); - struct rtentry *rt = NULL; struct llentry *ln = NULL; int is_newentry; - struct sockaddr_dl *sdl = NULL; int do_update; int olladdr; int llchange; int newstate = 0; + uint16_t router = 0; KASSERT(ifp != NULL); KASSERT(from != NULL); @@ -2041,50 +1862,31 @@ nd6_cache_lladdr( * description on it in NS section (RFC 2461 7.2.3). */ - rt = nd6_lookup(from, 0, ifp); - if (rt == NULL) { + ln = nd6_lookup(from, ifp, true); + if (ln == NULL) { #if 0 /* nothing must be done if there's no lladdr */ if (!lladdr || !lladdrlen) return NULL; #endif - rt = nd6_lookup(from, 1, ifp); + ln = nd6_create(from, ifp); is_newentry = 1; } else { /* do nothing if static ndp is set */ - if (rt->rt_flags & RTF_STATIC) { - rtfree(rt); + if (ln->la_flags & LLE_STATIC) { + LLE_WUNLOCK(ln); return; } is_newentry = 0; } - if (rt == NULL) - return; - if ((rt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO) { -fail: - if (rt->rt_llinfo != NULL) - LLE_WLOCK((struct llentry *)rt->rt_llinfo); - nd6_free(rt, rt->rt_llinfo, 0); - rtfree(rt); - return; - } - ln = rt->rt_llinfo; if (ln == NULL) - goto fail; - if (rt->rt_gateway == NULL) - goto fail; - if (rt->rt_gateway->sa_family != AF_LINK) - goto fail; - sdl = satosdl(rt->rt_gateway); + return; - olladdr = (sdl->sdl_alen) ? 1 : 0; + olladdr = (ln->la_flags & LLE_VALID) ? 1 : 0; if (olladdr && lladdr) { - if (memcmp(lladdr, CLLADDR(sdl), ifp->if_addrlen)) - llchange = 1; - else - llchange = 0; + llchange = memcmp(lladdr, &ln->ll_addr, ifp->if_addrlen); } else llchange = 0; @@ -2104,13 +1906,8 @@ fail: * Record source link-layer address * XXX is it dependent to ifp->if_type? */ - /* XXX check for error */ - if (sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr, - ifp->if_addrlen) == NULL) { - printf("%s.%d: sockaddr_dl_setaddr(, %d, ) " - "failed on %s\n", __func__, __LINE__, - sdl->sdl_len, if_name(ifp)); - } + memcpy(&ln->ll_addr, lladdr, ifp->if_addrlen); + ln->la_flags |= LLE_VALID; } if (!is_newentry) { @@ -2143,7 +1940,7 @@ fail: */ nd6_llinfo_settimer(ln, nd6_gctimer * hz); - nd6_llinfo_release_pkts(ln, ifp, rt); + nd6_llinfo_release_pkts(ln, ifp); } else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) { /* probe right away */ nd6_llinfo_settimer((void *)ln, 0); @@ -2215,8 +2012,23 @@ fail: break; } +#if 0 + /* XXX should we send rtmsg as it used to be? */ if (do_update) rt_newmsg(RTM_CHANGE, rt); /* tell user process */ +#endif + + if (ln != NULL) { + router = ln->ln_router; + LLE_WUNLOCK(ln); + } + + /* + * If we have too many cache entries, initiate immediate + * purging for some entries. + */ + if (is_newentry) + nd6_gc_neighbors(LLTABLE6(ifp)); /* * When the link-layer address of a router changes, select the @@ -2233,11 +2045,9 @@ fail: * for those are not autoconfigured hosts, we explicitly avoid such * cases for safety. */ - if (do_update && ln->ln_router && !ip6_forwarding && + if (do_update && router && !ip6_forwarding && nd6_accepts_rtadv(ndi)) defrouter_select(); - - rtfree(rt); } static void @@ -2268,112 +2078,14 @@ nd6_slowtimo(void *ignored_arg) mutex_exit(softnet_lock); } -/* - * Next hop determination. This routine was derived from ether_output. - */ -static int -nd6_determine_nexthop(struct ifnet *ifp, const struct sockaddr_in6 *dst, - struct rtentry *rt00, struct rtentry **ret_rt, bool *sendpkt) +int +nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m, + const struct sockaddr_in6 *dst, struct rtentry *rt) { - struct rtentry *rt, *rt0; - struct rtentry *gwrt; - struct sockaddr_in6 *gw6; - -#define RTFREE_IF_NEEDED(_rt) \ - if ((_rt) != NULL && (_rt) != rt00) \ - rtfree((_rt)); - - KASSERT(rt00 != NULL); - - rt = rt0 = rt00; - - if ((rt->rt_flags & RTF_UP) == 0) { - rt0 = rt = rtalloc1(sin6tocsa(dst), 1); - if (rt == NULL) - goto hostunreach; - if (rt->rt_ifp != ifp) - goto hostunreach; - } - - if ((rt->rt_flags & RTF_GATEWAY) == 0) - goto out; - - gw6 = (struct sockaddr_in6 *)rt->rt_gateway; - - /* - * We skip link-layer address resolution and NUD - * if the gateway is not a neighbor from ND point - * of view, regardless of the value of nd_ifinfo.flags. - * The second condition is a bit tricky; we skip - * if the gateway is our own address, which is - * sometimes used to install a route to a p2p link. - */ - if (!nd6_is_addr_neighbor(gw6, ifp) || - in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) { - /* - * We allow this kind of tricky route only - * when the outgoing interface is p2p. - * XXX: we may need a more generic rule here. - */ - if ((ifp->if_flags & IFF_POINTOPOINT) == 0) - goto hostunreach; - - *sendpkt = true; - goto out; - } - - /* Try to use a cached nexthop route (gwroute) if exists */ - gwrt = rt_get_gwroute(rt); - if (gwrt == NULL) - goto lookup; - - RTFREE_IF_NEEDED(rt); - rt = gwrt; - if ((rt->rt_flags & RTF_UP) == 0) { - RTFREE_IF_NEEDED(rt); - rt = rt0; - lookup: - /* Look up a nexthop route */ - gwrt = rtalloc1(rt->rt_gateway, 1); - rt_set_gwroute(rt, gwrt); - RTFREE_IF_NEEDED(rt); - rt = gwrt; - if (rt == NULL) - goto hostunreach; - /* the "G" test below also prevents rt == rt0 */ - if ((rt->rt_flags & RTF_GATEWAY) || - (rt->rt_ifp != ifp)) { - if (rt0->rt_gwroute != NULL) - rtfree(rt0->rt_gwroute); - rt0->rt_gwroute = NULL; - goto hostunreach; - } - } - -out: - *ret_rt = rt; - return 0; - -hostunreach: - RTFREE_IF_NEEDED(rt); - - return EHOSTUNREACH; -#undef RTFREE_IF_NEEDED -} - #define senderr(e) { error = (e); goto bad;} -int -nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, - const struct sockaddr_in6 *dst, struct rtentry *rt0) -{ - struct mbuf *m = m0; - struct rtentry *rt = rt0; struct llentry *ln = NULL; int error = 0; - -#define RTFREE_IF_NEEDED(_rt) \ - if ((_rt) != NULL && (_rt) != rt0) \ - rtfree((_rt)); + bool created = false; if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr)) goto sendpkt; @@ -2381,18 +2093,6 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, if (nd6_need_cache(ifp) == 0) goto sendpkt; - if (rt) { - struct rtentry *nexthop = NULL; - bool sendpkt = false; - - error = nd6_determine_nexthop(ifp, dst, rt, &nexthop, &sendpkt); - if (error != 0) - senderr(error); - rt = nexthop; - if (sendpkt) - goto sendpkt; - } - /* * Address resolution or Neighbor Unreachability Detection * for the next hop. @@ -2401,22 +2101,19 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, */ /* Look up the neighbor cache for the nexthop */ - if (rt != NULL && (rt->rt_flags & RTF_LLINFO) != 0) - ln = rt->rt_llinfo; - else { + ln = nd6_lookup(&dst->sin6_addr, ifp, true); + if ((ln == NULL) && nd6_is_addr_neighbor(dst, ifp)) { /* * Since nd6_is_addr_neighbor() internally calls nd6_lookup(), * the condition below is not very efficient. But we believe * it is tolerable, because this should be a rare case. */ - if (nd6_is_addr_neighbor(dst, ifp)) { - RTFREE_IF_NEEDED(rt); - rt = nd6_lookup(&dst->sin6_addr, 1, ifp); - if (rt != NULL) - ln = rt->rt_llinfo; - } + ln = nd6_create(&dst->sin6_addr, ifp); + if (ln != NULL) + created = true; } - if (ln == NULL || rt == NULL) { + + if (ln == NULL) { if ((ifp->if_flags & IFF_POINTOPOINT) == 0 && !(ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD)) { log(LOG_DEBUG, @@ -2425,10 +2122,11 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, ip6_sprintf(&dst->sin6_addr), ln, rt); senderr(EIO); /* XXX: good error? */ } - goto sendpkt; /* send anyway */ } + LLE_WLOCK_ASSERT(ln); + /* We don't have to do link-layer address resolution on a p2p link. */ if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && ln->ln_state < ND6_LLINFO_REACHABLE) { @@ -2496,11 +2194,16 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, struct in6_addr src, *psrc; ln->ln_asked++; - nd6_llinfo_settimer(ln, - ND_IFINFO(ifp)->retrans * hz / 1000); + nd6_llinfo_settimer(ln, ND_IFINFO(ifp)->retrans * hz / 1000); psrc = nd6_llinfo_get_holdsrc(ln, &src); + LLE_WUNLOCK(ln); + ln = NULL; nd6_ns_output(ifp, NULL, &dst->sin6_addr, psrc, 0); + } else { + /* We did the lookup so we need to do the unlock here. */ + LLE_WUNLOCK(ln); } + error = 0; goto exit; @@ -2511,6 +2214,9 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, goto bad; } + if (ln != NULL) + LLE_WUNLOCK(ln); + #ifndef NET_MPSAFE KERNEL_LOCK(1, NULL); #endif @@ -2527,12 +2233,12 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0, if (m != NULL) m_freem(m); exit: - RTFREE_IF_NEEDED(rt); + if (created) + nd6_gc_neighbors(LLTABLE6(ifp)); return error; -#undef RTFREE_IF_NEEDED -} #undef senderr +} int nd6_need_cache(struct ifnet *ifp) @@ -2559,12 +2265,67 @@ nd6_need_cache(struct ifnet *ifp) } } +/* + * Add pernament ND6 link-layer record for given + * interface address. + * + * Very similar to IPv4 arp_ifinit(), but: + * 1) IPv6 DAD is performed in different place + * 2) It is called by IPv6 protocol stack in contrast to + * arp_ifinit() which is typically called in SIOCSIFADDR + * driver ioctl handler. + * + */ +int +nd6_add_ifa_lle(struct in6_ifaddr *ia) +{ + struct ifnet *ifp; + struct llentry *ln; + + ifp = ia->ia_ifa.ifa_ifp; + if (nd6_need_cache(ifp) == 0) + return 0; + ia->ia_ifa.ifa_rtrequest = nd6_rtrequest; + ia->ia_ifa.ifa_flags = RTF_CONNECTED; + + IF_AFDATA_WLOCK(ifp); + ln = lla_create(LLTABLE6(ifp), LLE_IFADDR | LLE_EXCLUSIVE, + (struct sockaddr *)&ia->ia_addr); + IF_AFDATA_WUNLOCK(ifp); + if (ln == NULL) + return ENOBUFS; + + ln->la_expire = 0; /* for IPv6 this means permanent */ + ln->ln_state = ND6_LLINFO_REACHABLE; + + LLE_WUNLOCK(ln); + return 0; +} + +/* + * Removes ALL lle records for interface address prefix. + * XXXME: That's probably not we really want to do, we need + * to remove address record only and keep other records + * until we determine if given prefix is really going + * to be removed. + */ +void +nd6_rem_ifa_lle(struct in6_ifaddr *ia) +{ + struct sockaddr_in6 mask, addr; + + memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); + memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); + lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr, + (struct sockaddr *)&mask, LLE_STATIC); +} + int nd6_storelladdr(const struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m, const struct sockaddr *dst, uint8_t *lldst, size_t dstsize) { - const struct sockaddr_dl *sdl; + struct llentry *ln; if (m->m_flags & M_MCAST) { switch (ifp->if_type) { @@ -2586,22 +2347,20 @@ nd6_storelladdr(const struct ifnet *ifp, const struct rtentry *rt, } } - if (rt == NULL) { + /* + * the entry should have been created in nd6_store_lladdr + */ + ln = nd6_lookup(&satocsin6(dst)->sin6_addr, ifp, false); + if ((ln == NULL) || !(ln->la_flags & LLE_VALID)) { + if (ln != NULL) + LLE_RUNLOCK(ln); /* this could happen, if we could not allocate memory */ m_freem(m); return 0; } - if (rt->rt_gateway->sa_family != AF_LINK) { - char gbuf[256]; - char dbuf[LINK_ADDRSTRLEN]; - sockaddr_format(rt->rt_gateway, gbuf, sizeof(gbuf)); - printf("%s: bad gateway address type %s for dst %s" - " through interface %s\n", __func__, gbuf, - IN6_PRINT(dbuf, &satocsin6(dst)->sin6_addr), - if_name(ifp)); - m_freem(m); - return 0; - } + + /* XXX llentry should have addrlen? */ +#if 0 sdl = satocsdl(rt->rt_gateway); if (sdl->sdl_alen == 0 || sdl->sdl_alen > dstsize) { char sbuf[INET6_ADDRSTRLEN]; @@ -2614,8 +2373,12 @@ nd6_storelladdr(const struct ifnet *ifp, const struct rtentry *rt, m_freem(m); return 0; } +#endif + + memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen)); + + LLE_RUNLOCK(ln); - memcpy(lldst, CLLADDR(sdl), MIN(dstsize, sdl->sdl_alen)); return 1; } diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index f2e4177..e7df895 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -398,10 +398,10 @@ int nd6_is_addr_neighbor(const struct sockaddr_in6 *, struct ifnet *); void nd6_option_init(void *, int, union nd_opts *); struct nd_opt_hdr *nd6_option(union nd_opts *); int nd6_options(union nd_opts *); -struct rtentry *nd6_lookup(const struct in6_addr *, int, struct ifnet *); +struct llentry *nd6_lookup(const struct in6_addr *, const struct ifnet *, bool); +struct llentry *nd6_create(const struct in6_addr *, const struct ifnet *); void nd6_setmtu(struct ifnet *); void nd6_llinfo_settimer(struct llentry *, time_t); -void nd6_llinfo_settimer_locked(struct llentry *, time_t); void nd6_timer(void *); void nd6_purge(struct ifnet *, struct in6_ifextra *); void nd6_nud_hint(struct rtentry *); @@ -417,8 +417,9 @@ int nd6_storelladdr(const struct ifnet *, const struct rtentry *, struct mbuf *, const struct sockaddr *, uint8_t *, size_t); int nd6_sysctl(int, void *, size_t *, void *, size_t); int nd6_need_cache(struct ifnet *); -void nd6_llinfo_release_pkts(struct llentry *, struct ifnet *, - struct rtentry *); +void nd6_llinfo_release_pkts(struct llentry *, struct ifnet *); +int nd6_add_ifa_lle(struct in6_ifaddr *); +void nd6_rem_ifa_lle(struct in6_ifaddr *); /* nd6_nbr.c */ void nd6_na_input(struct mbuf *, int, int); diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index 1eba8de..df0a687 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -548,9 +548,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) char *lladdr = NULL; int lladdrlen = 0; struct ifaddr *ifa; - struct llentry *ln; - struct rtentry *rt = NULL; - struct sockaddr_dl *sdl; + struct llentry *ln = NULL; union nd_opts ndopts; struct sockaddr_in6 ssin6; int rt_announce; @@ -650,10 +648,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) * If no neighbor cache entry is found, NA SHOULD silently be * discarded. */ - rt = nd6_lookup(&taddr6, 0, ifp); - if ((rt == NULL) || - ((ln = rt->rt_llinfo) == NULL) || - ((sdl = satosdl(rt->rt_gateway)) == NULL)) + ln = nd6_lookup(&taddr6, ifp, true); + if (ln == NULL) goto freeit; rt_announce = 0; @@ -668,8 +664,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) /* * Record link-layer address, and update the state. */ - (void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, lladdr, - ifp->if_addrlen); + memcpy(&ln->ll_addr, lladdr, ifp->if_addrlen); + ln->la_flags |= LLE_VALID; rt_announce = 1; if (is_solicited) { ln->ln_state = ND6_LLINFO_REACHABLE; @@ -699,8 +695,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) if (lladdr == NULL) llchange = 0; else { - if (sdl->sdl_alen) { - if (memcmp(lladdr, CLLADDR(sdl), ifp->if_addrlen)) + if (ln->la_flags & LLE_VALID) { + if (memcmp(lladdr, &ln->ll_addr, ifp->if_addrlen)) llchange = rt_announce = 1; else llchange = 0; @@ -744,8 +740,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) * Update link-local address, if any. */ if (lladdr != NULL) { - (void)sockaddr_dl_setaddr(sdl, sdl->sdl_len, - lladdr, ifp->if_addrlen); + memcpy(&ln->ll_addr, lladdr, ifp->if_addrlen); + ln->la_flags |= LLE_VALID; } /* @@ -779,7 +775,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) const struct in6_addr *in6; int s; - in6 = &satocsin6(rt_getkey(rt))->sin6_addr; + in6 = &ln->r_l3addr.addr6; /* * Lock to protect the default router list. @@ -788,7 +784,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) * context. However, we keep it just for safety. */ s = splsoftnet(); - dr = defrouter_lookup(in6, rt->rt_ifp); + dr = defrouter_lookup(in6, ln->lle_tbl->llt_ifp); if (dr) defrtrlist_del(dr, NULL); else if (!ip6_forwarding) { @@ -799,25 +795,35 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len) * (e.g. redirect case). So we must * call rt6_flush explicitly. */ - rt6_flush(&ip6->ip6_src, rt->rt_ifp); + rt6_flush(&ip6->ip6_src, ln->lle_tbl->llt_ifp); } splx(s); } ln->ln_router = is_router; } - rt->rt_flags &= ~RTF_REJECT; + /* + * XXX: does this matter? + * rt->rt_flags &= ~RTF_REJECT; + */ ln->ln_asked = 0; - nd6_llinfo_release_pkts(ln, ifp, rt); + nd6_llinfo_release_pkts(ln, ifp); + /* FIXME */ +#if 0 if (rt_announce) /* tell user process about any new lladdr */ rt_newmsg(RTM_CHANGE, rt); +#endif freeit: + if (ln != NULL) + LLE_WUNLOCK(ln); + m_freem(m); - if (rt != NULL) - rtfree(rt); return; bad: + if (ln != NULL) + LLE_WUNLOCK(ln); + ICMP6_STATINC(ICMP6_STAT_BADNA); m_freem(m); } diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index 141487e..178aa2a 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -108,17 +108,18 @@ int nd6_numroutes = 0; static inline bool nd6_is_llinfo_probreach(struct nd_defrouter *dr) { - struct rtentry *rt = NULL; struct llentry *ln = NULL; - rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp); - if (rt == NULL) + ln = nd6_lookup(&dr->rtaddr, dr->ifp, false); + if (ln == NULL) return false; - ln = rt->rt_llinfo; - rtfree(rt); - if (ln == NULL || !ND6_IS_LLINFO_PROBREACH(ln)) + + if (!ND6_IS_LLINFO_PROBREACH(ln)) { + LLE_RUNLOCK(ln); return false; + } + LLE_RUNLOCK(ln); return true; } @@ -1673,12 +1674,12 @@ nd6_prefix_onlink(struct nd_prefix *pr) rtflags = ifa->ifa_flags | RTF_UP; if (nd6_need_cache(ifp)) { /* explicitly set in case ifa_flags does not set the flag. */ - rtflags |= RTF_CLONING; + rtflags |= RTF_CONNECTED; } else { /* * explicitly clear the cloning bit in case ifa_flags sets it. */ - rtflags &= ~RTF_CLONING; + rtflags &= ~RTF_CONNECTED; } error = rtrequest_newmsg(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix, ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags); diff --git a/tests/net/arp/t_arp.sh b/tests/net/arp/t_arp.sh index 6680859..519130a 100644 --- a/tests/net/arp/t_arp.sh +++ b/tests/net/arp/t_arp.sh @@ -232,7 +232,8 @@ command_body() atf_check -s not-exit:0 -e ignore rump.arp -n 10.0.1.13 atf_check -s not-exit:0 -e ignore rump.arp -n 10.0.1.14 atf_check -s not-exit:0 -e ignore rump.arp -n 10.0.1.15 - atf_check -s not-exit:0 -e ignore rump.arp -n 10.0.1.1 + # arp cache of the interface address isn't deleted + atf_check -s exit:0 -o match:'10.0.1.1' rump.arp -n 10.0.1.1 # Test temp option $DEBUG && rump.arp -n -a @@ -325,9 +326,9 @@ cache_overwriting_body() $DEBUG && rump.arp -n -a atf_check -s exit:0 -o match:'b2:a0:20:00:00:10' rump.arp -n 10.0.1.10 atf_check -s exit:0 -o not-match:'permanent' rump.arp -n 10.0.1.10 - # Cannot overwrite a temp cache - atf_check -s not-exit:0 -e match:'File exists' \ - rump.arp -s 10.0.1.10 b2:a0:20:00:00:ff + # Can overwrite a temp cache + atf_check -s exit:0 -o ignore rump.arp -s 10.0.1.10 b2:a0:20:00:00:ff + atf_check -s exit:0 -o match:'b2:a0:20:00:00:ff' rump.arp -n 10.0.1.10 $DEBUG && rump.arp -n -a return 0 @@ -342,6 +343,16 @@ make_pkt_str_arprep() echo $pkt } +make_pkt_str_garp() +{ + local ip=$1 + local mac=$2 + local pkt= + pkt="$mac > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806)," + pkt="$pkt length 42: Request who-has $ip tell $ip, length 28" + echo $pkt +} + extract_new_packets() { local old=./old @@ -357,16 +368,6 @@ extract_new_packets() cat ./diff } -check_entry_flags() -{ - local ip=$(echo $1 |sed 's/\./\\./g') - local flags=$2 - - atf_check -s exit:0 -o match:" $flags " -e ignore -x \ - "rump.netstat -rn -f inet | grep ^'$ip'" -} - - test_proxy_arp() { local arp_keep=5 @@ -386,11 +387,9 @@ test_proxy_arp() if [ "$type" = "pub" ]; then opts="pub" title="permanent published" - flags="ULSp" else opts="pub proxy" title='permanent published \(proxy only\)' - flags="UHLSp" fi # @@ -414,12 +413,6 @@ test_proxy_arp() atf_check -s exit:0 -o ignore \ rump.arp -s $IP4DST_PROXYARP1 $macaddr_dst $opts atf_check -s exit:0 -o match:"$title" rump.arp -n $IP4DST_PROXYARP1 - if [ "$type" = "pub" ]; then - # XXX local? Is it correct? - check_entry_flags $IP4DST_PROXYARP1 ${flags}l - else - check_entry_flags $IP4DST_PROXYARP1 $flags - fi # Try to ping export RUMP_SERVER=$SOCKSRC @@ -435,11 +428,13 @@ test_proxy_arp() extract_new_packets > ./out $DEBUG && cat ./out - pkt=$(make_pkt_str_arprep $IP4DST_PROXYARP1 $macaddr_dst) + pkt1=$(make_pkt_str_arprep $IP4DST_PROXYARP1 $macaddr_dst) + pkt2=$(make_pkt_str_garp $IP4DST_PROXYARP1 $macaddr_dst) if [ "$type" = "pub" ]; then - atf_check -s not-exit:0 -x "cat ./out |grep -q '$pkt'" + atf_check -s not-exit:0 -x \ + "cat ./out |grep -q -e '$pkt1' -e '$pkt2'" else - atf_check -s exit:0 -x "cat ./out |grep -q '$pkt'" + atf_check -s exit:0 -x "cat ./out |grep -q -e '$pkt1' -e '$pkt2'" fi # @@ -449,7 +444,7 @@ test_proxy_arp() atf_check -s exit:0 -o ignore \ rump.arp -s $IP4DST_PROXYARP2 $macaddr_dst $opts atf_check -s exit:0 -o match:"$title" rump.arp -n $IP4DST_PROXYARP2 - check_entry_flags $IP4DST_PROXYARP2 $flags + $DEBUG && rump.netstat -nr -f inet # Try to ping (should fail because no endpoint exists) export RUMP_SERVER=$SOCKSRC @@ -470,14 +465,7 @@ test_proxy_arp() # Try to ping export RUMP_SERVER=$SOCKSRC - if [ "$type" = "pub" ]; then - atf_check -s exit:0 -o ignore \ - rump.ping -n -w 1 -c 1 $IP4DST_PROXYARP2 - else - # XXX fails - atf_check -s not-exit:0 -o ignore -e ignore \ - rump.ping -n -w 1 -c 1 $IP4DST_PROXYARP2 - fi + atf_check -s exit:0 -o ignore rump.ping -n -w 1 -c 1 $IP4DST_PROXYARP2 } proxy_arp_pub_body() diff --git a/tests/net/if/t_ifconfig.sh b/tests/net/if/t_ifconfig.sh index 51b36ee..44ac4e9 100644 --- a/tests/net/if/t_ifconfig.sh +++ b/tests/net/if/t_ifconfig.sh @@ -261,6 +261,8 @@ parameters_body() atf_check -s not-exit:0 -o ignore -e ignore \ rump.ping -c 1 -w $TIMEOUT -n 192.168.0.3 atf_check -s exit:0 -o not-match:'192.168.0.3' rump.arp -an + # The entry shouldn't appear in the routing table anymore + atf_check -s exit:0 -o not-match:'192.168.0.3' rump.netstat -nr # netmask atf_check -s exit:0 rump.ifconfig shmif0 inet 172.16.0.1 netmask 255.255.255.0 alias diff --git a/tests/net/net/t_forwarding.sh b/tests/net/net/t_forwarding.sh index 59507ba..ff7d817 100644 --- a/tests/net/net/t_forwarding.sh +++ b/tests/net/net/t_forwarding.sh @@ -342,15 +342,6 @@ test_ping_success() atf_check -s exit:0 -o ignore rump.ping -q -n -w $TIMEOUT -c 1 $IP4DSTGW atf_check -s exit:0 -o ignore rump.ping -q -n -w $TIMEOUT -c 1 $IP4SRC $DEBUG && rump.ifconfig -v shmif0 - - # Check if nexthop lookup involving a rtentry creation - # on sending a packet works - export RUMP_SERVER=$SOCKSRC - $DEBUG && rump.netstat -nr - atf_check -s exit:0 -o ignore rump.route delete $IP4SRCGW - $DEBUG && rump.netstat -nr - atf_check -s exit:0 -o ignore rump.ping -q -n -w $TIMEOUT -c 2 $IP4DST - $DEBUG && rump.netstat -nr } test_ping_ttl() @@ -423,15 +414,6 @@ test_ping6_success() atf_check -s exit:0 -o ignore rump.ping6 -q -n -c 1 -X $TIMEOUT $IP6DSTGW atf_check -s exit:0 -o ignore rump.ping6 -q -n -c 1 -X $TIMEOUT $IP6SRC $DEBUG && rump.ifconfig -v shmif0 - - # Check if nexthop lookup involving a rtentry creation - # on sending a packet works - export RUMP_SERVER=$SOCKSRC - $DEBUG && rump.netstat -nr - atf_check -s exit:0 -o ignore rump.route delete -inet6 $IP6SRCGW - $DEBUG && rump.netstat -nr - atf_check -s exit:0 -o ignore rump.ping6 -q -n -c 2 -X $TIMEOUT $IP6DST - $DEBUG && rump.netstat -nr } test_hoplimit() diff --git a/tests/net/net/t_ipaddress.sh b/tests/net/net/t_ipaddress.sh index 556e761..42365bd 100644 --- a/tests/net/net/t_ipaddress.sh +++ b/tests/net/net/t_ipaddress.sh @@ -54,7 +54,6 @@ test_same_address() { local ip=10.0.0.1 local net=10.0.0/24 - local macaddr= atf_check -s exit:0 ${SERVER} ${SOCK_LOCAL} export RUMP_SERVER=$SOCK_LOCAL @@ -67,12 +66,10 @@ test_same_address() $DEBUG && rump.netstat -nr -f inet - macaddr=$(rump.ifconfig shmif0 |awk '/address/ {print $2}') - - check_entry $ip UHLl + check_entry $ip UHl check_entry $ip lo0 - check_entry $ip $macaddr - check_entry $net UC + check_entry $ip 'link#2' + check_entry $net U check_entry $net shmif0 check_entry $net 'link#2' @@ -90,10 +87,10 @@ test_same_address() $DEBUG && rump.netstat -nr -f inet - check_entry $ip UHLl + check_entry $ip UHl check_entry $ip lo0 - check_entry $ip $macaddr - check_entry $net UC + check_entry $ip 'link#2' + check_entry $net U check_entry $net shmif0 check_entry $net 'link#2' @@ -110,7 +107,6 @@ test_same_address6() { local ip=fc00::1 local net=fc00::/64 - local macaddr= atf_check -s exit:0 ${SERVER6} ${SOCK_LOCAL} export RUMP_SERVER=$SOCK_LOCAL @@ -123,12 +119,10 @@ test_same_address6() $DEBUG && rump.netstat -nr -f inet6 - macaddr=$(rump.ifconfig shmif0 |awk '/address/ {print $2}') - - check_entry $ip UHLl + check_entry $ip UHl check_entry $ip lo0 - check_entry $ip $macaddr - check_entry $net UC + check_entry $ip 'link#2' + check_entry $net U check_entry $net shmif0 check_entry $net 'link#2' @@ -146,10 +140,10 @@ test_same_address6() $DEBUG && rump.netstat -nr -f inet6 - check_entry $ip UHLl + check_entry $ip UHl check_entry $ip lo0 - check_entry $ip $macaddr - check_entry $net UC + check_entry $ip 'link#2' + check_entry $net U check_entry $net shmif0 check_entry $net 'link#2' diff --git a/tests/net/route/t_flags.sh b/tests/net/route/t_flags.sh index bd66473..af2475b 100644 --- a/tests/net/route/t_flags.sh +++ b/tests/net/route/t_flags.sh @@ -138,24 +138,12 @@ test_connected() export RUMP_SERVER=$SOCK_LOCAL # Up, Host, LLINFO, local - check_entry_flags 10.0.0.2 UHLl + check_entry_flags 10.0.0.2 UHl # Up, Cloning check_entry_flags 10.0.0/24 UC } -test_cloned() -{ - - export RUMP_SERVER=$SOCK_LOCAL - - atf_check -s exit:0 -o ignore rump.ping -n -w 1 -c 1 10.0.0.1 - $DEBUG && rump.netstat -rn -f inet - - # Up, Host, LLINFO, cloned - check_entry_flags 10.0.0.1 UHLc -} - test_default_gateway() { @@ -188,31 +176,6 @@ test_static() check_entry_flags 10.0.2/24 UGS } -test_route_flush() -{ - - export RUMP_SERVER=$SOCK_LOCAL - - # Reusing other tests to create routes - test_cloned_route - test_default_gateway - test_static_route - - atf_check -s exit:0 -o ignore rump.route flush - $DEBUG && rump.netstat -rn -f inet - - # Should remain - check_entry_flags 127.0.0.1 UHl - check_entry_flags 10.0.0/24 UC - - # Shouldn't remain - check_entry_fail default UGS - check_entry_fail 10.0.1.1 UGHS - check_entry_fail 10.0.2/24 UGS - # Should it remain? - check_entry_fail 10.0.0.2 UHLl -} - test_blackhole() { @@ -232,7 +195,7 @@ test_blackhole() $DEBUG && rump.netstat -rn -f inet # Shouldn't be created - check_entry_fail 10.0.0.1 UHLc + check_entry_fail 10.0.0.1 UH } test_reject() @@ -254,7 +217,7 @@ test_reject() $DEBUG && rump.netstat -rn -f inet # Shouldn't be created - check_entry_fail 10.0.0.1 UHLc + check_entry_fail 10.0.0.1 UH } test_icmp_redirect() @@ -332,56 +295,6 @@ test_announce() # TODO test its behavior } -test_xresolve_rtm() -{ - local ip=$1 - local rtm=$2 - local pid= - - rump.route -n monitor > ./mon.log & - pid=$! - - # Give route monitor a chance to setup a routing socket - sleep 1 - - atf_check -s exit:0 -o ignore rump.ping -n -w 1 -c 1 $ip - $DEBUG && rump.netstat -rn -f inet - - # Give route monitor a chance to output a routing message - sleep 1 - cat ./mon.log - - atf_check -s exit:0 grep -q $rtm ./mon.log - - kill $pid -} - -test_xresolve() -{ - - export RUMP_SERVER=$SOCK_LOCAL - - # For a normal route, a RTM_ADD message is emitted on a route cloning - test_xresolve_rtm 10.0.0.1 RTM_ADD - # Up, Host, LLINFO, cloned - check_entry_flags 10.0.0.1 UHLc - - # Delete an existing route first - atf_check -s exit:0 -o ignore rump.route delete -net 10.0.0.0/24 - # Create a connected route with XRESOLVE flag for the interface - atf_check -s exit:0 -o ignore rump.route add -net 10.0.0.0/24 10.0.0.2 \ - -interface -xresolve - $DEBUG && rump.netstat -rn -f inet - - # Up, Cloning, Xresolve, Static - check_entry_flags 10.0.0/24 UCXS - - # If XRESOLVE flag is set, a RTM_RESOLVE message is emitted - test_xresolve_rtm 10.0.0.1 RTM_RESOLVE - # Up, Host, Xresolve, LLINFO, cloned - check_entry_flags 10.0.0.1 UHXLc -} - cleanup() { $DEBUG && /usr/bin/shmif_dumpbus -p - $BUS 2>/dev/null | \ @@ -416,12 +329,10 @@ atf_init_test_cases() add_test lo "Tests route flags: loop back interface" add_test connected "Tests route flags: connected route" - add_test cloned "Tests route flags: cloned route" add_test default_gateway "Tests route flags: default gateway" add_test static "Tests route flags: static route" add_test blackhole "Tests route flags: blackhole route" add_test reject "Tests route flags: reject route" add_test icmp_redirect "Tests route flags: icmp redirect" add_test announce "Tests route flags: announce flag" - add_test xresolve "Tests route flags: xresolve flag" } diff --git a/usr.sbin/arp/arp.c b/usr.sbin/arp/arp.c index 53d6940..ecb4b83 100644 --- a/usr.sbin/arp/arp.c +++ b/usr.sbin/arp/arp.c @@ -263,7 +263,7 @@ static int set(int argc, char **argv) { struct sockaddr_inarp *sina; - struct sockaddr_dl *sdl; + struct sockaddr_dl *sdl = NULL; struct rt_msghdr *rtm; char *host = argv[0], *eaddr; struct sockaddr_inarp sin_m = blank_sin; /* struct copy */ @@ -309,8 +309,6 @@ set(int argc, char **argv) } } - if (memcmp(&sdl_m, &blank_sdl, sizeof(blank_sdl))) - goto out; tryagain: rtm = rtmsg(s, RTM_GET, &sin_m, &sdl_m); if (rtm == NULL) { @@ -343,7 +341,6 @@ overwrite: } sdl_m.sdl_type = sdl->sdl_type; sdl_m.sdl_index = sdl->sdl_index; -out: sin_m.sin_other = 0; if (doing_proxy && export_only) sin_m.sin_other = SIN_PROXY; @@ -373,7 +370,7 @@ static int is_llinfo(const struct sockaddr_dl *sdl, int rtflags) { if (sdl->sdl_family != AF_LINK || - (rtflags & (RTF_LLINFO|RTF_GATEWAY)) != RTF_LLINFO) + (rtflags & (RTF_LLDATA|RTF_GATEWAY)) != RTF_LLDATA) return 0; switch (sdl->sdl_type) { @@ -635,8 +632,11 @@ rtmsg(const int s, const int cmd, const struct sockaddr_inarp *sin, cp = m_rtmsg.m_space; errno = 0; - if (cmd == RTM_DELETE) + /* XXX depends on rtm is filled by RTM_GET */ + if (cmd == RTM_DELETE) { + rtm->rtm_flags |= RTF_LLDATA; goto doit; + } (void)memset(&m_rtmsg, 0, sizeof(m_rtmsg)); rtm->rtm_flags = flags; rtm->rtm_version = RTM_VERSION; @@ -649,16 +649,17 @@ rtmsg(const int s, const int cmd, const struct sockaddr_inarp *sin, rtm->rtm_addrs |= RTA_GATEWAY; rtm->rtm_rmx.rmx_expire = expire_time; rtm->rtm_inits = RTV_EXPIRE; - rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); + rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); if (doing_proxy) { if (!export_only) { rtm->rtm_addrs |= RTA_NETMASK; rtm->rtm_flags &= ~RTF_HOST; } } - /* FALLTHROUGH */ - case RTM_GET: rtm->rtm_addrs |= RTA_DST; + break; + case RTM_GET: + rtm->rtm_addrs |= RTA_DST | RTA_IFP; } #define NEXTADDR(w, s) \ diff --git a/usr.sbin/ldpd/mpls_routes.c b/usr.sbin/ldpd/mpls_routes.c index 3555c10..d2bf9b1 100644 --- a/usr.sbin/ldpd/mpls_routes.c +++ b/usr.sbin/ldpd/mpls_routes.c @@ -625,7 +625,7 @@ check_route(struct rt_msg * rg, uint rlen) if (rg->m_rtm.rtm_addrs & RTA_GATEWAY) { GETNEXT(so_gate, so_dest); - if ((rg->m_rtm.rtm_flags & RTF_CLONING) == 0 && + if ((rg->m_rtm.rtm_flags & RTF_CONNECTED) == 0 && so_gate->sa.sa_family != AF_INET && so_gate->sa.sa_family != AF_MPLS) return LDP_E_OK; @@ -651,7 +651,7 @@ check_route(struct rt_msg * rg, uint rlen) so_pref->sin.sin_port = 0; memset(&so_pref->sin.sin_zero, 0, sizeof(so_pref->sin.sin_zero)); - if (rg->m_rtm.rtm_flags & RTF_CLONING) + if (rg->m_rtm.rtm_flags & RTF_CONNECTED) so_gate = NULL; switch (rg->m_rtm.rtm_type) { diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c index ccda821..a34a0e8 100644 --- a/usr.sbin/ndp/ndp.c +++ b/usr.sbin/ndp/ndp.c @@ -394,7 +394,6 @@ set(int argc, char **argv) sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(mysin->sin6_len) + (char *)(void *)mysin); if (IN6_ARE_ADDR_EQUAL(&mysin->sin6_addr, &sin_m.sin6_addr)) { if (sdl->sdl_family == AF_LINK && - (rtm->rtm_flags & RTF_LLINFO) && !(rtm->rtm_flags & RTF_GATEWAY)) { switch (sdl->sdl_type) { case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: @@ -478,7 +477,6 @@ delete(char *host) (char *)(void *)mysin); if (IN6_ARE_ADDR_EQUAL(&mysin->sin6_addr, &sin_m.sin6_addr)) { if (sdl->sdl_family == AF_LINK && - (rtm->rtm_flags & RTF_LLINFO) && !(rtm->rtm_flags & RTF_GATEWAY)) { goto delete; } @@ -602,15 +600,8 @@ again:; host_buf, sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0)); if (cflag) { -#ifdef RTF_WASCLONED - if (rtm->rtm_flags & RTF_WASCLONED) + if ((rtm->rtm_flags & RTF_STATIC) == 0) (void)delete(host_buf); -#elif defined(RTF_CLONED) - if (rtm->rtm_flags & RTF_CLONED) - (void)delete(host_buf); -#else - (void)delete(host_buf); -#endif continue; } (void)gettimeofday(&tim, 0); @@ -806,8 +797,10 @@ rtmsg(int cmd) register int l; errno = 0; - if (cmd == RTM_DELETE) + if (cmd == RTM_DELETE) { + rtm->rtm_flags |= RTF_LLDATA; goto doit; + } (void)memset(&m_rtmsg, 0, sizeof(m_rtmsg)); rtm->rtm_flags = flags; rtm->rtm_version = RTM_VERSION; @@ -822,16 +815,17 @@ rtmsg(int cmd) rtm->rtm_rmx.rmx_expire = expire_time; rtm->rtm_inits = RTV_EXPIRE; } - rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); + rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); #ifdef notdef /* we don't support ipv6addr/128 type proxying. */ if (rtm->rtm_flags & RTF_ANNOUNCE) { rtm->rtm_flags &= ~RTF_HOST; rtm->rtm_addrs |= RTA_NETMASK; } #endif - /* FALLTHROUGH */ - case RTM_GET: rtm->rtm_addrs |= RTA_DST; + break; + case RTM_GET: + rtm->rtm_addrs |= RTA_DST | RTA_IFP; } #define NEXTADDR(w, s) \ if (rtm->rtm_addrs & (w)) { \ diff --git a/usr.sbin/route6d/route6d.c b/usr.sbin/route6d/route6d.c index 96dd84b..c109360 100644 --- a/usr.sbin/route6d/route6d.c +++ b/usr.sbin/route6d/route6d.c @@ -1983,7 +1983,7 @@ ifrt(struct ifc *ifcp, int again) if (ifa->ifa_plen == 128) rrt->rrt_flags = RTF_HOST; else - rrt->rrt_flags = RTF_CLONING; + rrt->rrt_flags = RTF_CONNECTED; rrt->rrt_rflags |= RRTF_CHANGED; applyplen(&rrt->rrt_info.rip6_dest, ifa->ifa_plen); memset(&rrt->rrt_gw, 0, sizeof(struct in6_addr));