Date: Thu, 12 Dec 2013 00:01:45 +0000 (UTC) From: "Andrey V. Elsukov" <ae@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r259239 - user/ae/inet6/sys/net Message-ID: <201312120001.rBC01jM9017200@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 <netinet/if_ether.h> #include <netinet/ip_carp.h> #ifdef INET6 -#include <netinet6/ip6_var.h> +#include <netinet6/in6_var.h> #include <netinet6/scope6_var.h> #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)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201312120001.rBC01jM9017200>