Remove deembed_scopeid sysctl, we don't use embedded address now. Add special handling for IPv6 LLA since we don't have LLA in routing tables now. --- sys/net/rtsock.c (svn+ssh://svn.freebsd.org/base/head) (revision 261548) +++ sys/net/rtsock.c (working copy) @@ -65,7 +65,7 @@ #include #include #ifdef INET6 -#include +#include #include #endif @@ -500,7 +500,6 @@ rtm_get_jailed(struct rt_addrinfo *info, struct if #ifdef INET6 case AF_INET6: { - struct in6_addr ia6; struct ifaddr *ifa; int found; @@ -511,33 +510,30 @@ rtm_get_jailed(struct rt_addrinfo *info, struct if */ IF_ADDR_RLOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { - struct sockaddr *sa; - sa = ifa->ifa_addr; - if (sa->sa_family != AF_INET6) + if (ifa->ifa_addr->sa_family != AF_INET6) continue; - bcopy(&((struct sockaddr_in6 *)sa)->sin6_addr, - &ia6, sizeof(struct in6_addr)); - if (prison_check_ip6(cred, &ia6) == 0) { + if (prison_if(cred, ifa->ifa_addr) == 0) { found = 1; break; } } IF_ADDR_RUNLOCK(ifp); + bzero(&saun->sin6, sizeof(struct sockaddr_in6)); + saun->sin6.sin6_len = sizeof(struct sockaddr_in6); + saun->sin6.sin6_family = AF_INET6; if (!found) { /* * As a last resort return the 'default' jail address. */ - ia6 = ((struct sockaddr_in6 *)rt->rt_ifa->ifa_addr)-> - sin6_addr; - if (prison_get_ip6(cred, &ia6) != 0) + if (prison_get_ip6(cred, &saun->sin6) != 0) return (ESRCH); + } else { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + saun->sin6.sin6_addr = sin6->sin6_addr; + saun->sin6.sin6_scope_id = sin6->sin6_scope_id; } - bzero(&saun->sin6, sizeof(struct sockaddr_in6)); - saun->sin6.sin6_len = sizeof(struct sockaddr_in6); - saun->sin6.sin6_family = AF_INET6; - bcopy(&ia6, &saun->sin6.sin6_addr, sizeof(struct in6_addr)); - if (sa6_recoverscope(&saun->sin6) != 0) - return (ESRCH); info->rti_info[RTAX_IFA] = (struct sockaddr *)&saun->sin6; break; } @@ -548,6 +544,70 @@ rtm_get_jailed(struct rt_addrinfo *info, struct if return (0); } +#ifdef INET6 +static int +in6_rt_handle_lla(struct rt_msghdr **ortm, struct rt_addrinfo *info) +{ + struct sockaddr_dl sdl; + struct sockaddr_in6 *sin6; + struct rt_msghdr *rtm = *ortm; + struct llentry *lle; + struct ifnet *ifp; + int i; + + if (rtm->rtm_type != RTM_GET) + return (EOPNOTSUPP); + sin6 = (struct sockaddr_in6 *)info->rti_info[RTAX_DST]; + if (sin6->sin6_scope_id == 0) + return (EADDRNOTAVAIL); + ifp = in6_getlinkifnet(sin6->sin6_scope_id); + if (ifp == NULL) + return (ESRCH); + /* Clear all sockaddr pointers except DST */ + for (i = RTAX_GATEWAY; i < RTAX_MAX; i++) + info->rti_info[i] = NULL; + + IF_AFDATA_RLOCK(ifp); + lle = lla_lookup(LLTABLE6(ifp), 0, info->rti_info[RTAX_DST]); + IF_AFDATA_RUNLOCK(ifp); + if (lle != NULL) { + bzero(&sdl, sizeof(sdl)); + info->rti_info[RTAX_GATEWAY] = (struct sockaddr *)&sdl; + sdl.sdl_family = AF_LINK; + sdl.sdl_len = sizeof(sdl); + sdl.sdl_alen = ifp->if_addrlen; + sdl.sdl_index = ifp->if_index; + sdl.sdl_type = ifp->if_type; + bcopy(&lle->ll_addr, LLADDR(&sdl), ifp->if_addrlen); + if (lle->la_flags & LLE_PUB) + rtm->rtm_flags |= RTF_ANNOUNCE; + if (lle->la_flags & LLE_STATIC) { + rtm->rtm_flags |= RTF_STATIC; + rtm->rtm_rmx.rmx_expire = 0; + } else + rtm->rtm_rmx.rmx_expire = lle->la_expire; + LLE_RUNLOCK(lle); + } else + info->rti_info[RTAX_GATEWAY] = ifp->if_addr->ifa_addr; + rtm->rtm_flags |= RTF_UP | RTF_HOST; + rtm->rtm_index = ifp->if_index; + if (rtm->rtm_addrs & (RTA_IFA | RTA_IFP)) + info->rti_info[RTAX_IFP] = ifp->if_addr->ifa_addr; + i = rt_msg2(rtm->rtm_type, info, NULL, NULL); + if (i > rtm->rtm_msglen) { + R_Malloc(rtm, struct rt_msghdr *, i); + if (rtm == NULL) + return (ENOBUFS); + bcopy(*ortm, rtm, i); + Free(*ortm); + *ortm = rtm; + } + rt_msg2(rtm->rtm_type, info, (caddr_t)rtm, NULL); + rtm->rtm_addrs = info->rti_addrs; + return (0); +} +#endif + /*ARGSUSED*/ static int route_output(struct mbuf *m, struct socket *so) @@ -557,11 +617,6 @@ route_output(struct mbuf *m, struct socket *so) struct rtentry *rt = NULL; struct radix_node_head *rnh; struct rt_addrinfo info; -#ifdef INET6 - struct sockaddr_storage ss; - struct sockaddr_in6 *sin6; - int i, rti_need_deembed = 0; -#endif int len, error = 0; struct ifnet *ifp = NULL; union sockaddr_union saun; @@ -592,11 +647,6 @@ 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); @@ -665,18 +715,11 @@ 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,10 +736,6 @@ 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, @@ -706,15 +745,22 @@ 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: case RTM_CHANGE: case RTM_LOCK: +#ifdef INET6 + if (info.rti_info[RTAX_DST]->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)info.rti_info[RTAX_DST]; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + error = in6_rt_handle_lla(&rtm, &info); + break; + } + } +#endif rnh = rt_tables_get_rnh(so->so_fibnum, info.rti_info[RTAX_DST]->sa_family); if (rnh == NULL) @@ -953,22 +999,6 @@ flush: rp = sotorawcb(so); } if (rtm) { -#ifdef INET6 - if (rti_need_deembed) { - /* sin6_scope_id is recovered before sending rtm. */ - sin6 = (struct sockaddr_in6 *)&ss; - for (i = 0; i < RTAX_MAX; i++) { - 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); @@ -1063,9 +1093,13 @@ rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_add } /* accept it */ #ifdef INET6 + /* + * XXX: some software use embedded scope ids. + * We remove id from address and initialize sin6_scope_id + * instead. + */ if (sa->sa_family == AF_INET6) - sa6_embedscope((struct sockaddr_in6 *)sa, - V_ip6_use_defzone); + sa6_recoverscope((struct sockaddr_in6 *)sa); #endif rtinfo->rti_info[i] = sa; cp += SA_SIZE(sa); @@ -1081,13 +1115,8 @@ rt_msg1(int type, struct rt_addrinfo *rtinfo) { struct rt_msghdr *rtm; struct mbuf *m; - int i; struct sockaddr *sa; -#ifdef INET6 - struct sockaddr_storage ss; - struct sockaddr_in6 *sin6; -#endif - int len, dlen; + int len, i; switch (type) { @@ -1130,17 +1159,8 @@ rt_msg1(int type, struct rt_addrinfo *rtinfo) if ((sa = rtinfo->rti_info[i]) == NULL) 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 - m_copyback(m, len, dlen, (caddr_t)sa); - len += dlen; + m_copyback(m, len, SA_SIZE(sa), (caddr_t)sa); + len += SA_SIZE(sa); } if (m->m_pkthdr.len != len) { m_freem(m); @@ -1158,13 +1178,8 @@ rt_msg1(int type, struct rt_addrinfo *rtinfo) static int rt_msg2(int type, struct rt_addrinfo *rtinfo, caddr_t cp, struct walkarg *w) { - int i; - int len, dlen, second_time = 0; caddr_t cp0; -#ifdef INET6 - struct sockaddr_storage ss; - struct sockaddr_in6 *sin6; -#endif + int len, i, second_time = 0; rtinfo->rti_addrs = 0; again: @@ -1215,20 +1230,11 @@ again: if ((sa = rtinfo->rti_info[i]) == NULL) continue; rtinfo->rti_addrs |= (1 << i); - dlen = SA_SIZE(sa); 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; + bcopy((caddr_t)sa, cp, SA_SIZE(sa)); + cp += SA_SIZE(sa); } - len += dlen; + len += SA_SIZE(sa); } len = ALIGN(len); if (cp == NULL && w != NULL && !second_time) {