From owner-svn-src-user@FreeBSD.ORG Thu Dec 12 00:01:45 2013 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 9B1DB3D6; Thu, 12 Dec 2013 00:01:45 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 87A3E1639; Thu, 12 Dec 2013 00:01:45 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id rBC01j9F017201; Thu, 12 Dec 2013 00:01:45 GMT (envelope-from ae@svn.freebsd.org) Received: (from ae@localhost) by svn.freebsd.org (8.14.7/8.14.7/Submit) id rBC01jM9017200; Thu, 12 Dec 2013 00:01:45 GMT (envelope-from ae@svn.freebsd.org) Message-Id: <201312120001.rBC01jM9017200@svn.freebsd.org> From: "Andrey V. Elsukov" Date: Thu, 12 Dec 2013 00:01:45 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r259239 - user/ae/inet6/sys/net X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 12 Dec 2013 00:01:45 -0000 Author: ae Date: Thu Dec 12 00:01:45 2013 New Revision: 259239 URL: http://svnweb.freebsd.org/changeset/base/259239 Log: We don't keep routes for link-local addresses in routing tables, thus we need to handle them specially in RTM_GET. This fixes some issues with ndp(8). If requested destination address has AF_INET6 family and it is from link-local scope, use sin6_scope_id to determine corresponding interface. Then do link layer address lookup. If address is in ND cache, return it, if not - return default AF_LINK ifaddr from this interface. Modified: user/ae/inet6/sys/net/rtsock.c Modified: user/ae/inet6/sys/net/rtsock.c ============================================================================== --- user/ae/inet6/sys/net/rtsock.c Wed Dec 11 23:28:31 2013 (r259238) +++ user/ae/inet6/sys/net/rtsock.c Thu Dec 12 00:01:45 2013 (r259239) @@ -66,7 +66,7 @@ #include #include #ifdef INET6 -#include +#include #include #endif @@ -558,6 +558,70 @@ rtm_get_jailed(struct rt_addrinfo *info, 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) @@ -700,6 +764,17 @@ route_output(struct mbuf *m, struct sock 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)