diff --git a/sbin/route/route.c b/sbin/route/route.c index 809dc9f08404..be85184f182e 100644 --- a/sbin/route/route.c +++ b/sbin/route/route.c @@ -1215,16 +1215,6 @@ getaddr(int which, char *str, struct hostent **hpp) exit(1); } memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); -#ifdef __KAME__ - if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) || - IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr) || - IN6_IS_ADDR_MC_NODELOCAL(&su->sin6.sin6_addr)) && - su->sin6.sin6_scope_id) { - *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = - htons(su->sin6.sin6_scope_id); - su->sin6.sin6_scope_id = 0; - } -#endif freeaddrinfo(res); if (q != NULL) *q++ = '/'; diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index a4d7407814e2..9a08a764def0 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -65,6 +65,7 @@ #include #include #ifdef INET6 +#include #include #endif @@ -175,14 +176,6 @@ MTX_SYSINIT(rtsock, &rtsock_mtx, "rtsock route_cb lock", MTX_DEF); #define RTSOCK_LOCK_ASSERT() mtx_assert(&rtsock_mtx, MA_OWNED) static SYSCTL_NODE(_net, OID_AUTO, route, CTLFLAG_RD, 0, ""); -#ifdef INET6 -static VNET_DEFINE(int, deembed_scopeid) = 1; -#define V_deembed_scopeid VNET(deembed_scopeid) -SYSCTL_DECL(_net_inet6_ip6); -SYSCTL_VNET_INT(_net_inet6_ip6, OID_AUTO, deembed_scopeid, CTLFLAG_RW, - &VNET_NAME(deembed_scopeid), 0, - "Extract embedded zone ID and set it to sin6_scope_id in sockaddr_in6."); -#endif struct walkarg { int w_tmemsize; @@ -572,9 +565,9 @@ route_output(struct mbuf *m, struct socket *so) struct radix_node_head *rnh; struct rt_addrinfo info; #ifdef INET6 - struct sockaddr_storage ss_dst; - struct sockaddr_storage ss_gw; + struct sockaddr_storage ss; struct sockaddr_in6 *sin6; + int i, rti_need_deembed = 0; #endif int len, error = 0; struct ifnet *ifp = NULL; @@ -606,6 +599,11 @@ route_output(struct mbuf *m, struct socket *so) rtm->rtm_pid = curproc->p_pid; bzero(&info, sizeof(info)); info.rti_addrs = rtm->rtm_addrs; + /* + * rt_xaddrs() performs s6_addr[2] := sin6_scope_id for AF_INET6 + * link-local address because rtrequest requires addresses with + * embedded scope id. + */ if (rt_xaddrs((caddr_t)(rtm + 1), len + (caddr_t)rtm, &info)) { info.rti_info[RTAX_DST] = NULL; senderr(EINVAL); @@ -672,11 +670,18 @@ route_output(struct mbuf *m, struct socket *so) if (info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK && (rtm->rtm_flags & RTF_LLDATA) != 0) { error = lla_rt_output(rtm, &info); +#ifdef INET6 + if (error == 0) + rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; +#endif break; } error = rtrequest1_fib(RTM_ADD, &info, &saved_nrt, so->so_fibnum); if (error == 0 && saved_nrt) { +#ifdef INET6 + rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; +#endif RT_LOCK(saved_nrt); rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, &saved_nrt->rt_rmx); @@ -693,6 +698,10 @@ route_output(struct mbuf *m, struct socket *so) (info.rti_info[RTAX_GATEWAY]->sa_family == AF_LINK) && (rtm->rtm_flags & RTF_LLDATA) != 0) { error = lla_rt_output(rtm, &info); +#ifdef INET6 + if (error == 0) + rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; +#endif break; } error = rtrequest1_fib(RTM_DELETE, &info, &saved_nrt, @@ -702,6 +711,10 @@ route_output(struct mbuf *m, struct socket *so) rt = saved_nrt; goto report; } +#ifdef INET6 + /* rt_msg2() will not be used when RTM_DELETE fails. */ + rti_need_deembed = (V_deembed_scopeid) ? 1 : 0; +#endif break; case RTM_GET: @@ -803,34 +816,7 @@ route_output(struct mbuf *m, struct socket *so) senderr(ESRCH); } info.rti_info[RTAX_DST] = rt_key(rt); -#ifdef INET6 - if (V_deembed_scopeid) { - switch (rt_key(rt)->sa_family) { - case AF_INET6: - sin6 = (struct sockaddr_in6 *)&ss_dst; - bcopy(rt_key(rt), sin6, sizeof(*sin6)); - if (sa6_recoverscope(sin6) == 0) - info.rti_info[RTAX_DST] = - (struct sockaddr *)sin6; - break; - } - } -#endif info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; -#ifdef INET6 - if (V_deembed_scopeid) { - switch (rt->rt_gateway->sa_family) { - case AF_INET6: - sin6 = (struct sockaddr_in6 *)&ss_gw; - bcopy(rt->rt_gateway, sin6, - sizeof(*sin6)); - if (sa6_recoverscope(sin6) == 0) - info.rti_info[RTAX_GATEWAY] = - (struct sockaddr *)sin6; - break; - } - } -#endif info.rti_info[RTAX_NETMASK] = rt_mask(rt); info.rti_info[RTAX_GENMASK] = 0; if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) { @@ -972,6 +958,22 @@ route_output(struct mbuf *m, struct socket *so) rp = sotorawcb(so); } if (rtm) { +#ifdef INET6 + if (rti_need_deembed) { + /* sin6_scope_id is recovered before sending rtm. */ + for (i = 0; i < RTAX_MAX; i++) { + sin6 = (struct sockaddr_in6 *)&ss; + if (info.rti_info[i] == NULL) + continue; + if (info.rti_info[i]->sa_family != AF_INET6) + continue; + bcopy(info.rti_info[i], sin6, sizeof(*sin6)); + if (sa6_recoverscope(sin6) == 0) + bcopy(sin6, info.rti_info[i], + sizeof(*sin6)); + } + } +#endif m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm); if (m->m_pkthdr.len < rtm->rtm_msglen) { m_freem(m); @@ -1065,6 +1067,11 @@ rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) return (0); /* should be EINVAL but for compat */ } /* accept it */ +#ifdef INET6 + if (sa->sa_family == AF_INET6) + sa6_embedscope((struct sockaddr_in6 *)sa, + V_ip6_use_defzone); +#endif rtinfo->rti_info[i] = sa; cp += SA_SIZE(sa); } @@ -1217,15 +1224,15 @@ rt_msg2(int type, struct rt_addrinfo *rtinfo, caddr_t cp, struct walkarg *w) continue; rtinfo->rti_addrs |= (1 << i); dlen = SA_SIZE(sa); -#ifdef INET6 - if (V_deembed_scopeid && sa->sa_family == AF_INET6) { - sin6 = (struct sockaddr_in6 *)&ss; - bcopy(sa, sin6, sizeof(*sin6)); - if (sa6_recoverscope(sin6) == 0) - sa = (struct sockaddr *)sin6; - } -#endif if (cp) { +#ifdef INET6 + if (V_deembed_scopeid && sa->sa_family == AF_INET6) { + sin6 = (struct sockaddr_in6 *)&ss; + bcopy(sa, sin6, sizeof(*sin6)); + if (sa6_recoverscope(sin6) == 0) + sa = (struct sockaddr *)sin6; + } +#endif bcopy((caddr_t)sa, cp, (unsigned)dlen); cp += dlen; } @@ -1565,11 +1572,6 @@ sysctl_dumpentry(struct radix_node *rn, void *vw) struct rtentry *rt = (struct rtentry *)rn; int error = 0, size; struct rt_addrinfo info; -#ifdef INET6 - struct sockaddr_storage ss[RTAX_MAX]; - struct sockaddr_in6 *sin6; - int i; -#endif if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) return 0; @@ -1588,20 +1590,6 @@ sysctl_dumpentry(struct radix_node *rn, void *vw) if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) info.rti_info[RTAX_BRD] = rt->rt_ifa->ifa_dstaddr; } -#ifdef INET6 - if (V_deembed_scopeid) { - for (i = 0; i < RTAX_MAX; i++) { - if (info.rti_info[i] == NULL) - continue; - if (info.rti_info[i]->sa_family != AF_INET6) - continue; - sin6 = (struct sockaddr_in6 *)&ss[i]; - bcopy(info.rti_info[i], sin6, sizeof(*sin6)); - if (sa6_recoverscope(sin6) == 0) - info.rti_info[i] = (struct sockaddr *)sin6; - } - } -#endif size = rt_msg2(RTM_GET, &info, NULL, w); if (w->w_req && w->w_tmem) { struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index 63b64ee5ad44..8da46cf47ee5 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -2669,6 +2669,8 @@ in6_lltable_dump(struct lltable *llt, struct sysctl_req *wr) ndpc.sin6.sin6_family = AF_INET6; ndpc.sin6.sin6_len = sizeof(ndpc.sin6); bcopy(L3_ADDR(lle), &ndpc.sin6, L3_ADDR_LEN(lle)); + if (V_deembed_scopeid) + sa6_recoverscope(&ndpc.sin6); /* publish */ if (lle->la_flags & LLE_PUB) diff --git a/sys/netinet6/scope6.c b/sys/netinet6/scope6.c index edfb1e626cd1..060fe59fe650 100644 --- a/sys/netinet6/scope6.c +++ b/sys/netinet6/scope6.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -55,6 +56,11 @@ VNET_DEFINE(int, ip6_use_defzone) = 1; #else VNET_DEFINE(int, ip6_use_defzone) = 0; #endif +VNET_DEFINE(int, deembed_scopeid) = 1; +SYSCTL_DECL(_net_inet6_ip6); +SYSCTL_VNET_INT(_net_inet6_ip6, OID_AUTO, deembed_scopeid, CTLFLAG_RW, + &VNET_NAME(deembed_scopeid), 0, + "Extract embedded zone ID and set it to sin6_scope_id in sockaddr_in6."); /* * The scope6_lock protects the global sid default stored in @@ -379,8 +385,11 @@ sa6_recoverscope(struct sockaddr_in6 *sin6) /* sanity check */ if (V_if_index < zoneid) return (ENXIO); +#if 0 + /* XXX: Disabled due to possible deadlock. */ if (!ifnet_byindex(zoneid)) return (ENXIO); +#endif if (sin6->sin6_scope_id != 0 && zoneid != sin6->sin6_scope_id) { log(LOG_NOTICE, diff --git a/sys/netinet6/scope6_var.h b/sys/netinet6/scope6_var.h index ae337b860a9e..87de8d71d615 100644 --- a/sys/netinet6/scope6_var.h +++ b/sys/netinet6/scope6_var.h @@ -34,6 +34,8 @@ #define _NETINET6_SCOPE6_VAR_H_ #ifdef _KERNEL +#include + struct scope6_id { /* * 16 is correspondent to 4bit multicast scope field. @@ -42,6 +44,9 @@ struct scope6_id { u_int32_t s6id_list[16]; }; +VNET_DECLARE(int, deembed_scopeid); +#define V_deembed_scopeid VNET(deembed_scopeid) + void scope6_init(void); struct scope6_id *scope6_ifattach(struct ifnet *); void scope6_ifdetach(struct scope6_id *); diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c index be21d0fc24a3..b50ddb78c7c0 100644 --- a/usr.sbin/ndp/ndp.c +++ b/usr.sbin/ndp/ndp.c @@ -404,12 +404,8 @@ set(argc, argv) return 1; } sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; -#ifdef __KAME__ - if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { - *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = - htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); - } -#endif + sin->sin6_scope_id = + ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; ea = (u_char *)LLADDR(&sdl_m); if (ndp_ether_aton(eaddr, ea) == 0) sdl_m.sdl_alen = 6; @@ -478,12 +474,6 @@ get(host) return; } sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; -#ifdef __KAME__ - if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { - *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = - htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); - } -#endif dump(&sin->sin6_addr, 0); if (found_entry == 0) { getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, @@ -520,12 +510,8 @@ delete(host) return 1; } sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; -#ifdef __KAME__ - if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { - *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = - htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); - } -#endif + sin->sin6_scope_id = + ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; if (rtmsg(RTM_GET) < 0) { errx(1, "RTM_GET(%s) failed", host); /* NOTREACHED */ @@ -556,16 +542,8 @@ delete(host) NEXTADDR(RTA_DST, sin_m); rtm->rtm_flags |= RTF_LLDATA; if (rtmsg(RTM_DELETE) == 0) { - struct sockaddr_in6 s6 = *sin; /* XXX: for safety */ - -#ifdef __KAME__ - if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) { - s6.sin6_scope_id = ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]); - *(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0; - } -#endif - getnameinfo((struct sockaddr *)&s6, - s6.sin6_len, host_buf, + getnameinfo((struct sockaddr *)sin, + sin->sin6_len, host_buf, sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0)); printf("%s (%s) deleted\n", host, host_buf); @@ -666,10 +644,6 @@ again:; /* XXX: should scope id be filled in the kernel? */ if (sin->sin6_scope_id == 0) sin->sin6_scope_id = sdl->sdl_index; -#ifdef __KAME__ - /* KAME specific hack; removed the embedded id */ - *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0; -#endif } getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0)); @@ -1331,22 +1305,6 @@ plist() p6.sin6_len = sizeof(p6); p6.sin6_addr = PR.prefix; #endif - - /* - * copy link index to sin6_scope_id field. - * XXX: KAME specific. - */ - if (IN6_IS_ADDR_LINKLOCAL(&p6.sin6_addr)) { - u_int16_t linkid; - - memcpy(&linkid, &p6.sin6_addr.s6_addr[2], - sizeof(linkid)); - linkid = ntohs(linkid); - p6.sin6_scope_id = linkid; - p6.sin6_addr.s6_addr[2] = 0; - p6.sin6_addr.s6_addr[3] = 0; - } - niflags = NI_NUMERICHOST; if (getnameinfo((struct sockaddr *)&p6, sizeof(p6), namebuf, sizeof(namebuf),