Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
/* $NetBSD: nd6_rtr.c,v 1.54 2006/01/21 00:15:37 rpaulo Exp $ */
|
2001-02-07 11:59:47 +03:00
|
|
|
/* $KAME: nd6_rtr.c,v 1.95 2001/02/07 08:09:47 itojun Exp $ */
|
1999-07-04 01:24:45 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* All rights reserved.
|
2000-06-13 06:54:11 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the project nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
2000-06-13 06:54:11 +04:00
|
|
|
*
|
1999-06-28 10:36:47 +04:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2001-11-13 03:56:55 +03:00
|
|
|
#include <sys/cdefs.h>
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.54 2006/01/21 00:15:37 rpaulo Exp $");
|
2001-11-13 03:56:55 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/errno.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/syslog.h>
|
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/if_types.h>
|
|
|
|
#include <net/if_dl.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
#include <net/radix.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet6/in6_var.h>
|
2000-02-06 15:49:37 +03:00
|
|
|
#include <netinet/ip6.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
#include <netinet6/ip6_var.h>
|
|
|
|
#include <netinet6/nd6.h>
|
2000-02-06 15:49:37 +03:00
|
|
|
#include <netinet/icmp6.h>
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
#include <netinet6/scope6_var.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
#include <net/net_osdep.h>
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
#define SDL(s) ((struct sockaddr_dl *)s)
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
static int rtpref __P((struct nd_defrouter *));
|
1999-06-28 10:36:47 +04:00
|
|
|
static struct nd_defrouter *defrtrlist_update __P((struct nd_defrouter *));
|
2002-06-09 01:22:29 +04:00
|
|
|
static struct in6_ifaddr *in6_ifadd __P((struct nd_prefix *));
|
1999-06-28 10:36:47 +04:00
|
|
|
static struct nd_pfxrouter *pfxrtr_lookup __P((struct nd_prefix *,
|
2002-06-09 01:22:29 +04:00
|
|
|
struct nd_defrouter *));
|
1999-06-28 10:36:47 +04:00
|
|
|
static void pfxrtr_add __P((struct nd_prefix *, struct nd_defrouter *));
|
|
|
|
static void pfxrtr_del __P((struct nd_pfxrouter *));
|
2002-06-09 01:22:29 +04:00
|
|
|
static struct nd_pfxrouter *find_pfxlist_reachable_router
|
|
|
|
__P((struct nd_prefix *));
|
|
|
|
static void defrouter_delreq __P((struct nd_defrouter *));
|
|
|
|
static void nd6_rtmsg __P((int, struct rtentry *));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
static void in6_init_address_ltimes __P((struct nd_prefix *ndpr,
|
2002-06-09 01:22:29 +04:00
|
|
|
struct in6_addrlifetime *lt6));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
static int rt6_deleteroute __P((struct radix_node *, void *));
|
|
|
|
|
|
|
|
extern int nd6_recalc_reachtm_interval;
|
|
|
|
|
2001-12-18 06:04:02 +03:00
|
|
|
static struct ifnet *nd6_defifp;
|
1999-12-13 18:17:17 +03:00
|
|
|
int nd6_defifindex;
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Receive Router Solicitation Message - just for routers.
|
|
|
|
* Router solicitation/advertisement is mostly managed by userland program
|
|
|
|
* (rtadvd) so here we have no function like nd6_ra_output().
|
|
|
|
*
|
|
|
|
* Based on RFC 2461
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nd6_rs_input(m, off, icmp6len)
|
|
|
|
struct mbuf *m;
|
|
|
|
int off, icmp6len;
|
|
|
|
{
|
|
|
|
struct ifnet *ifp = m->m_pkthdr.rcvif;
|
|
|
|
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
2000-02-26 11:39:18 +03:00
|
|
|
struct nd_router_solicit *nd_rs;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct in6_addr saddr6 = ip6->ip6_src;
|
|
|
|
#if 0
|
|
|
|
struct in6_addr daddr6 = ip6->ip6_dst;
|
|
|
|
#endif
|
|
|
|
char *lladdr = NULL;
|
|
|
|
int lladdrlen = 0;
|
|
|
|
#if 0
|
|
|
|
struct sockaddr_dl *sdl = (struct sockaddr_dl *)NULL;
|
|
|
|
struct llinfo_nd6 *ln = (struct llinfo_nd6 *)NULL;
|
|
|
|
struct rtentry *rt = NULL;
|
|
|
|
int is_newentry;
|
|
|
|
#endif
|
|
|
|
union nd_opts ndopts;
|
|
|
|
|
|
|
|
/* If I'm not a router, ignore it. */
|
2003-06-24 11:54:47 +04:00
|
|
|
if (ip6_accept_rtadv != 0 || !ip6_forwarding)
|
2000-02-26 11:39:18 +03:00
|
|
|
goto freeit;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* Sanity checks */
|
|
|
|
if (ip6->ip6_hlim != 255) {
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_ERR,
|
|
|
|
"nd6_rs_input: invalid hlim (%d) from %s to %s on %s\n",
|
|
|
|
ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
|
|
|
|
ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
|
|
|
|
goto bad;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't update the neighbor cache, if src = ::.
|
|
|
|
* This indicates that the src has no IP address assigned yet.
|
|
|
|
*/
|
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
|
2000-02-26 11:39:18 +03:00
|
|
|
goto freeit;
|
|
|
|
|
|
|
|
IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
|
|
|
|
if (nd_rs == NULL) {
|
|
|
|
icmp6stat.icp6s_tooshort++;
|
1999-06-28 10:36:47 +04:00
|
|
|
return;
|
2000-02-26 11:39:18 +03:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
icmp6len -= sizeof(*nd_rs);
|
|
|
|
nd6_option_init(nd_rs + 1, icmp6len, &ndopts);
|
|
|
|
if (nd6_options(&ndopts) < 0) {
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_INFO,
|
|
|
|
"nd6_rs_input: invalid ND option, ignored\n"));
|
|
|
|
/* nd6_options have incremented stats */
|
2000-02-26 11:39:18 +03:00
|
|
|
goto freeit;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ndopts.nd_opts_src_lladdr) {
|
|
|
|
lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
|
|
|
|
lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_INFO,
|
1999-06-28 10:36:47 +04:00
|
|
|
"nd6_rs_input: lladdrlen mismatch for %s "
|
|
|
|
"(if %d, RS packet %d)\n",
|
2002-06-09 01:22:29 +04:00
|
|
|
ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2));
|
2001-02-07 11:59:47 +03:00
|
|
|
goto bad;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
1999-07-31 22:41:15 +04:00
|
|
|
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_SOLICIT, 0);
|
2000-02-26 11:39:18 +03:00
|
|
|
|
|
|
|
freeit:
|
|
|
|
m_freem(m);
|
2001-02-07 11:59:47 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
bad:
|
|
|
|
icmp6stat.icp6s_badrs++;
|
|
|
|
m_freem(m);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Receive Router Advertisement Message.
|
|
|
|
*
|
|
|
|
* Based on RFC 2461
|
|
|
|
* TODO: on-link bit on prefix information
|
|
|
|
* TODO: ND_RA_FLAG_{OTHER,MANAGED} processing
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nd6_ra_input(m, off, icmp6len)
|
|
|
|
struct mbuf *m;
|
|
|
|
int off, icmp6len;
|
|
|
|
{
|
|
|
|
struct ifnet *ifp = m->m_pkthdr.rcvif;
|
2002-05-29 11:53:39 +04:00
|
|
|
struct nd_ifinfo *ndi = ND_IFINFO(ifp);
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
|
2000-02-26 11:39:18 +03:00
|
|
|
struct nd_router_advert *nd_ra;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct in6_addr saddr6 = ip6->ip6_src;
|
|
|
|
#if 0
|
|
|
|
struct in6_addr daddr6 = ip6->ip6_dst;
|
2000-02-26 11:39:18 +03:00
|
|
|
int flags; /* = nd_ra->nd_ra_flags_reserved; */
|
1999-06-28 10:36:47 +04:00
|
|
|
int is_managed = ((flags & ND_RA_FLAG_MANAGED) != 0);
|
|
|
|
int is_other = ((flags & ND_RA_FLAG_OTHER) != 0);
|
|
|
|
#endif
|
|
|
|
union nd_opts ndopts;
|
|
|
|
struct nd_defrouter *dr;
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* We only accept RAs only when
|
|
|
|
* the system-wide variable allows the acceptance, and
|
2002-06-09 18:43:10 +04:00
|
|
|
* per-interface variable allows RAs on the receiving interface.
|
2002-06-09 01:22:29 +04:00
|
|
|
*/
|
1999-06-28 10:36:47 +04:00
|
|
|
if (ip6_accept_rtadv == 0)
|
2000-02-26 11:39:18 +03:00
|
|
|
goto freeit;
|
2002-06-09 01:22:29 +04:00
|
|
|
if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
|
|
|
|
goto freeit;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (ip6->ip6_hlim != 255) {
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_ERR,
|
|
|
|
"nd6_ra_input: invalid hlim (%d) from %s to %s on %s\n",
|
|
|
|
ip6->ip6_hlim, ip6_sprintf(&ip6->ip6_src),
|
|
|
|
ip6_sprintf(&ip6->ip6_dst), if_name(ifp)));
|
|
|
|
goto bad;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!IN6_IS_ADDR_LINKLOCAL(&saddr6)) {
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_ERR,
|
1999-06-28 10:36:47 +04:00
|
|
|
"nd6_ra_input: src %s is not link-local\n",
|
2001-02-07 11:59:47 +03:00
|
|
|
ip6_sprintf(&saddr6)));
|
|
|
|
goto bad;
|
2000-02-26 11:39:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
|
|
|
|
if (nd_ra == NULL) {
|
|
|
|
icmp6stat.icp6s_tooshort++;
|
1999-06-28 10:36:47 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
icmp6len -= sizeof(*nd_ra);
|
|
|
|
nd6_option_init(nd_ra + 1, icmp6len, &ndopts);
|
|
|
|
if (nd6_options(&ndopts) < 0) {
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_INFO,
|
|
|
|
"nd6_ra_input: invalid ND option, ignored\n"));
|
|
|
|
/* nd6_options have incremented stats */
|
2000-02-26 11:39:18 +03:00
|
|
|
goto freeit;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2005-05-30 01:43:51 +04:00
|
|
|
struct nd_defrouter drtr;
|
1999-06-28 10:36:47 +04:00
|
|
|
u_int32_t advreachable = nd_ra->nd_ra_reachable;
|
|
|
|
|
2005-05-30 01:43:51 +04:00
|
|
|
Bzero(&drtr, sizeof(drtr));
|
|
|
|
drtr.rtaddr = saddr6;
|
|
|
|
drtr.flags = nd_ra->nd_ra_flags_reserved;
|
|
|
|
drtr.rtlifetime = ntohs(nd_ra->nd_ra_router_lifetime);
|
|
|
|
drtr.expire = time.tv_sec + drtr.rtlifetime;
|
|
|
|
drtr.ifp = ifp;
|
1999-06-28 10:36:47 +04:00
|
|
|
/* unspecified or not? (RFC 2461 6.3.4) */
|
|
|
|
if (advreachable) {
|
|
|
|
NTOHL(advreachable);
|
|
|
|
if (advreachable <= MAX_REACHABLE_TIME &&
|
|
|
|
ndi->basereachable != advreachable) {
|
|
|
|
ndi->basereachable = advreachable;
|
|
|
|
ndi->reachable = ND_COMPUTE_RTIME(ndi->basereachable);
|
|
|
|
ndi->recalctm = nd6_recalc_reachtm_interval; /* reset */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (nd_ra->nd_ra_retransmit)
|
|
|
|
ndi->retrans = ntohl(nd_ra->nd_ra_retransmit);
|
|
|
|
if (nd_ra->nd_ra_curhoplimit)
|
|
|
|
ndi->chlim = nd_ra->nd_ra_curhoplimit;
|
2005-05-30 01:43:51 +04:00
|
|
|
dr = defrtrlist_update(&drtr);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* prefix
|
|
|
|
*/
|
|
|
|
if (ndopts.nd_opts_pi) {
|
|
|
|
struct nd_opt_hdr *pt;
|
2002-06-09 01:22:29 +04:00
|
|
|
struct nd_opt_prefix_info *pi = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct nd_prefix pr;
|
|
|
|
|
|
|
|
for (pt = (struct nd_opt_hdr *)ndopts.nd_opts_pi;
|
|
|
|
pt <= (struct nd_opt_hdr *)ndopts.nd_opts_pi_end;
|
|
|
|
pt = (struct nd_opt_hdr *)((caddr_t)pt +
|
|
|
|
(pt->nd_opt_len << 3))) {
|
|
|
|
if (pt->nd_opt_type != ND_OPT_PREFIX_INFORMATION)
|
|
|
|
continue;
|
|
|
|
pi = (struct nd_opt_prefix_info *)pt;
|
|
|
|
|
|
|
|
if (pi->nd_opt_pi_len != 4) {
|
2001-04-04 10:28:41 +04:00
|
|
|
nd6log((LOG_INFO,
|
|
|
|
"nd6_ra_input: invalid option "
|
|
|
|
"len %d for prefix information option, "
|
|
|
|
"ignored\n", pi->nd_opt_pi_len));
|
1999-06-28 10:36:47 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (128 < pi->nd_opt_pi_prefix_len) {
|
2001-04-04 10:28:41 +04:00
|
|
|
nd6log((LOG_INFO,
|
|
|
|
"nd6_ra_input: invalid prefix "
|
|
|
|
"len %d for prefix information option, "
|
|
|
|
"ignored\n", pi->nd_opt_pi_prefix_len));
|
1999-06-28 10:36:47 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix)
|
|
|
|
|| IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix)) {
|
2001-04-04 10:28:41 +04:00
|
|
|
nd6log((LOG_INFO,
|
|
|
|
"nd6_ra_input: invalid prefix "
|
|
|
|
"%s, ignored\n",
|
|
|
|
ip6_sprintf(&pi->nd_opt_pi_prefix)));
|
1999-06-28 10:36:47 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* aggregatable unicast address, rfc2374 */
|
|
|
|
if ((pi->nd_opt_pi_prefix.s6_addr8[0] & 0xe0) == 0x20
|
|
|
|
&& pi->nd_opt_pi_prefix_len != 64) {
|
2001-04-04 10:28:41 +04:00
|
|
|
nd6log((LOG_INFO,
|
|
|
|
"nd6_ra_input: invalid prefixlen "
|
|
|
|
"%d for rfc2374 prefix %s, ignored\n",
|
|
|
|
pi->nd_opt_pi_prefix_len,
|
|
|
|
ip6_sprintf(&pi->nd_opt_pi_prefix)));
|
1999-06-28 10:36:47 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bzero(&pr, sizeof(pr));
|
|
|
|
pr.ndpr_prefix.sin6_family = AF_INET6;
|
|
|
|
pr.ndpr_prefix.sin6_len = sizeof(pr.ndpr_prefix);
|
|
|
|
pr.ndpr_prefix.sin6_addr = pi->nd_opt_pi_prefix;
|
|
|
|
pr.ndpr_ifp = (struct ifnet *)m->m_pkthdr.rcvif;
|
|
|
|
|
|
|
|
pr.ndpr_raf_onlink = (pi->nd_opt_pi_flags_reserved &
|
2002-06-09 01:22:29 +04:00
|
|
|
ND_OPT_PI_FLAG_ONLINK) ? 1 : 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
pr.ndpr_raf_auto = (pi->nd_opt_pi_flags_reserved &
|
2002-06-09 01:22:29 +04:00
|
|
|
ND_OPT_PI_FLAG_AUTO) ? 1 : 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
pr.ndpr_plen = pi->nd_opt_pi_prefix_len;
|
|
|
|
pr.ndpr_vltime = ntohl(pi->nd_opt_pi_valid_time);
|
2002-06-09 01:22:29 +04:00
|
|
|
pr.ndpr_pltime = ntohl(pi->nd_opt_pi_preferred_time);
|
2003-06-24 11:39:24 +04:00
|
|
|
pr.ndpr_lastupdate = time.tv_sec;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (in6_init_prefix_ltimes(&pr))
|
|
|
|
continue; /* prefix lifetime init failed */
|
|
|
|
|
|
|
|
(void)prelist_update(&pr, dr, m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* MTU
|
|
|
|
*/
|
|
|
|
if (ndopts.nd_opts_mtu && ndopts.nd_opts_mtu->nd_opt_mtu_len == 1) {
|
2002-06-09 01:22:29 +04:00
|
|
|
u_long mtu;
|
2002-06-07 07:05:18 +04:00
|
|
|
u_long maxmtu;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/* lower bound */
|
|
|
|
if (mtu < IPV6_MMTU) {
|
2001-04-04 10:28:41 +04:00
|
|
|
nd6log((LOG_INFO, "nd6_ra_input: bogus mtu option "
|
2002-06-09 01:22:29 +04:00
|
|
|
"mtu=%lu sent from %s, ignoring\n",
|
2001-04-04 10:28:41 +04:00
|
|
|
mtu, ip6_sprintf(&ip6->ip6_src)));
|
1999-06-28 10:36:47 +04:00
|
|
|
goto skip;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* upper bound */
|
2002-06-07 07:05:18 +04:00
|
|
|
maxmtu = (ndi->maxmtu && ndi->maxmtu < ifp->if_mtu)
|
|
|
|
? ndi->maxmtu : ifp->if_mtu;
|
|
|
|
if (mtu <= maxmtu) {
|
|
|
|
int change = (ndi->linkmtu != mtu);
|
|
|
|
|
|
|
|
ndi->linkmtu = mtu;
|
|
|
|
if (change) /* in6_maxmtu may change */
|
|
|
|
in6_setmaxmtu();
|
1999-06-28 10:36:47 +04:00
|
|
|
} else {
|
2002-06-07 07:05:18 +04:00
|
|
|
nd6log((LOG_INFO, "nd6_ra_input: bogus mtu "
|
2002-06-09 01:22:29 +04:00
|
|
|
"mtu=%lu sent from %s; "
|
2002-06-07 07:05:18 +04:00
|
|
|
"exceeds maxmtu %lu, ignoring\n",
|
|
|
|
mtu, ip6_sprintf(&ip6->ip6_src), maxmtu));
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
skip:
|
2002-06-09 18:43:10 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
2001-10-17 14:55:09 +04:00
|
|
|
* Source link layer address
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
{
|
|
|
|
char *lladdr = NULL;
|
|
|
|
int lladdrlen = 0;
|
2002-06-09 18:43:10 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
if (ndopts.nd_opts_src_lladdr) {
|
|
|
|
lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
|
|
|
|
lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
|
2001-02-07 11:59:47 +03:00
|
|
|
nd6log((LOG_INFO,
|
1999-06-28 10:36:47 +04:00
|
|
|
"nd6_ra_input: lladdrlen mismatch for %s "
|
2002-06-07 07:05:18 +04:00
|
|
|
"(if %d, RA packet %d)\n", ip6_sprintf(&saddr6),
|
|
|
|
ifp->if_addrlen, lladdrlen - 2));
|
2001-02-07 11:59:47 +03:00
|
|
|
goto bad;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
1999-07-31 22:41:15 +04:00
|
|
|
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0);
|
1999-12-13 18:17:17 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Installing a link-layer address might change the state of the
|
|
|
|
* router's neighbor cache, which might also affect our on-link
|
|
|
|
* detection of adveritsed prefixes.
|
|
|
|
*/
|
|
|
|
pfxlist_onlink_check();
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2000-02-26 11:39:18 +03:00
|
|
|
|
2001-02-07 11:59:47 +03:00
|
|
|
freeit:
|
|
|
|
m_freem(m);
|
|
|
|
return;
|
|
|
|
|
|
|
|
bad:
|
|
|
|
icmp6stat.icp6s_badra++;
|
2000-02-26 11:39:18 +03:00
|
|
|
m_freem(m);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2003-09-27 02:23:58 +04:00
|
|
|
* default router list processing sub routines
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
|
|
|
|
/* tell the change to user processes watching the routing socket. */
|
|
|
|
static void
|
|
|
|
nd6_rtmsg(cmd, rt)
|
|
|
|
int cmd;
|
|
|
|
struct rtentry *rt;
|
|
|
|
{
|
|
|
|
struct rt_addrinfo info;
|
|
|
|
|
|
|
|
bzero((caddr_t)&info, sizeof(info));
|
|
|
|
info.rti_info[RTAX_DST] = rt_key(rt);
|
|
|
|
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
|
|
|
|
info.rti_info[RTAX_NETMASK] = rt_mask(rt);
|
2003-05-15 18:57:58 +04:00
|
|
|
if (rt->rt_ifp) {
|
2003-05-16 20:57:35 +04:00
|
|
|
info.rti_info[RTAX_IFP] =
|
|
|
|
TAILQ_FIRST(&rt->rt_ifp->if_addrlist)->ifa_addr;
|
2003-05-15 18:57:58 +04:00
|
|
|
info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
|
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
|
|
|
|
rt_missmsg(cmd, &info, rt->rt_flags, 0);
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
void
|
|
|
|
defrouter_addreq(new)
|
|
|
|
struct nd_defrouter *new;
|
|
|
|
{
|
|
|
|
struct sockaddr_in6 def, mask, gate;
|
2002-06-09 01:22:29 +04:00
|
|
|
struct rtentry *newrt = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
int s;
|
2002-06-09 01:22:29 +04:00
|
|
|
int error;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
Bzero(&def, sizeof(def));
|
|
|
|
Bzero(&mask, sizeof(mask));
|
2002-06-09 01:22:29 +04:00
|
|
|
Bzero(&gate, sizeof(gate)); /* for safety */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
def.sin6_len = mask.sin6_len = gate.sin6_len =
|
|
|
|
sizeof(struct sockaddr_in6);
|
1999-06-28 10:36:47 +04:00
|
|
|
def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
|
|
|
|
gate.sin6_addr = new->rtaddr;
|
2002-06-09 01:22:29 +04:00
|
|
|
#ifndef SCOPEDROUTING
|
|
|
|
gate.sin6_scope_id = 0; /* XXX */
|
|
|
|
#endif
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1999-07-04 06:01:15 +04:00
|
|
|
s = splsoftnet();
|
2002-06-09 01:22:29 +04:00
|
|
|
error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
|
|
|
|
(struct sockaddr *)&gate, (struct sockaddr *)&mask,
|
|
|
|
RTF_GATEWAY, &newrt);
|
|
|
|
if (newrt) {
|
|
|
|
nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
|
|
|
|
newrt->rt_refcnt--;
|
|
|
|
}
|
|
|
|
if (error == 0)
|
|
|
|
new->installed = 1;
|
1999-06-28 10:36:47 +04:00
|
|
|
splx(s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct nd_defrouter *
|
|
|
|
defrouter_lookup(addr, ifp)
|
|
|
|
struct in6_addr *addr;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
{
|
|
|
|
struct nd_defrouter *dr;
|
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
|
|
|
|
dr = TAILQ_NEXT(dr, dr_entry)) {
|
2002-06-09 01:22:29 +04:00
|
|
|
if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) {
|
2002-09-11 06:46:42 +04:00
|
|
|
return (dr);
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
1999-12-13 18:17:17 +03:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (NULL); /* search failed */
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
defrtrlist_del(dr)
|
|
|
|
struct nd_defrouter *dr;
|
|
|
|
{
|
|
|
|
struct nd_defrouter *deldr = NULL;
|
|
|
|
struct nd_prefix *pr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Flush all the routing table entries that use the router
|
|
|
|
* as a next hop.
|
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
if (!ip6_forwarding && ip6_accept_rtadv) /* XXX: better condition? */
|
1999-06-28 10:36:47 +04:00
|
|
|
rt6_flush(&dr->rtaddr, dr->ifp);
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
if (dr->installed) {
|
|
|
|
deldr = dr;
|
|
|
|
defrouter_delreq(dr);
|
|
|
|
}
|
1999-12-13 18:17:17 +03:00
|
|
|
TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Also delete all the pointers to the router in each prefix lists.
|
|
|
|
*/
|
|
|
|
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
|
|
|
|
struct nd_pfxrouter *pfxrtr;
|
|
|
|
if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
|
|
|
|
pfxrtr_del(pfxrtr);
|
|
|
|
}
|
|
|
|
pfxlist_onlink_check();
|
|
|
|
|
|
|
|
/*
|
1999-12-13 18:17:17 +03:00
|
|
|
* If the router is the primary one, choose a new one.
|
|
|
|
* Note that defrouter_select() will remove the current gateway
|
|
|
|
* from the routing table.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
if (deldr)
|
1999-12-13 18:17:17 +03:00
|
|
|
defrouter_select();
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
free(dr, M_IP6NDP);
|
|
|
|
}
|
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* Remove the default route for a given router.
|
|
|
|
* This is just a subroutine function for defrouter_select(), and should
|
|
|
|
* not be called from anywhere else.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
defrouter_delreq(dr)
|
|
|
|
struct nd_defrouter *dr;
|
|
|
|
{
|
|
|
|
struct sockaddr_in6 def, mask, gw;
|
|
|
|
struct rtentry *oldrt = NULL;
|
|
|
|
|
2002-07-31 03:24:21 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (!dr)
|
|
|
|
panic("dr == NULL in defrouter_delreq");
|
|
|
|
#endif
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
Bzero(&def, sizeof(def));
|
|
|
|
Bzero(&mask, sizeof(mask));
|
|
|
|
Bzero(&gw, sizeof(gw)); /* for safety */
|
|
|
|
|
|
|
|
def.sin6_len = mask.sin6_len = gw.sin6_len =
|
|
|
|
sizeof(struct sockaddr_in6);
|
|
|
|
def.sin6_family = mask.sin6_family = gw.sin6_family = AF_INET6;
|
|
|
|
gw.sin6_addr = dr->rtaddr;
|
|
|
|
#ifndef SCOPEDROUTING
|
|
|
|
gw.sin6_scope_id = 0; /* XXX */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
rtrequest(RTM_DELETE, (struct sockaddr *)&def,
|
2002-07-31 03:24:21 +04:00
|
|
|
(struct sockaddr *)&gw,
|
2002-06-09 01:22:29 +04:00
|
|
|
(struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
|
|
|
|
if (oldrt) {
|
|
|
|
nd6_rtmsg(RTM_DELETE, oldrt);
|
|
|
|
if (oldrt->rt_refcnt <= 0) {
|
|
|
|
/*
|
|
|
|
* XXX: borrowed from the RTM_DELETE case of
|
|
|
|
* rtrequest().
|
|
|
|
*/
|
|
|
|
oldrt->rt_refcnt++;
|
|
|
|
rtfree(oldrt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-07-31 03:24:21 +04:00
|
|
|
dr->installed = 0;
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* remove all default routes from default router list
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
defrouter_reset()
|
|
|
|
{
|
|
|
|
struct nd_defrouter *dr;
|
|
|
|
|
|
|
|
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
|
|
|
|
dr = TAILQ_NEXT(dr, dr_entry))
|
|
|
|
defrouter_delreq(dr);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX should we also nuke any default routers in the kernel, by
|
|
|
|
* going through them by rtalloc1()?
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Default Router Selection according to Section 6.3.6 of RFC 2461 and
|
|
|
|
* draft-ietf-ipngwg-router-selection:
|
|
|
|
* 1) Routers that are reachable or probably reachable should be preferred.
|
|
|
|
* If we have more than one (probably) reachable router, prefer ones
|
|
|
|
* with the highest router preference.
|
1999-12-13 18:17:17 +03:00
|
|
|
* 2) When no routers on the list are known to be reachable or
|
|
|
|
* probably reachable, routers SHOULD be selected in a round-robin
|
2002-06-09 01:22:29 +04:00
|
|
|
* fashion, regardless of router preference values.
|
1999-12-13 18:17:17 +03:00
|
|
|
* 3) If the Default Router List is empty, assume that all
|
|
|
|
* destinations are on-link.
|
2002-06-09 01:22:29 +04:00
|
|
|
*
|
|
|
|
* We assume nd_defrouter is sorted by router preference value.
|
|
|
|
* Since the code below covers both with and without router preference cases,
|
|
|
|
* we do not need to classify the cases by ifdef.
|
|
|
|
*
|
|
|
|
* At this moment, we do not try to install more than one default router,
|
|
|
|
* even when the multipath routing is available, because we're not sure about
|
|
|
|
* the benefits for stub hosts comparing to the risk of making the code
|
|
|
|
* complicated and the possibility of introducing bugs.
|
1999-12-13 18:17:17 +03:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
defrouter_select()
|
|
|
|
{
|
|
|
|
int s = splsoftnet();
|
2002-06-09 01:22:29 +04:00
|
|
|
struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;
|
1999-12-13 18:17:17 +03:00
|
|
|
struct rtentry *rt = NULL;
|
|
|
|
struct llinfo_nd6 *ln = NULL;
|
|
|
|
|
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* This function should be called only when acting as an autoconfigured
|
|
|
|
* host. Although the remaining part of this function is not effective
|
|
|
|
* if the node is not an autoconfigured host, we explicitly exclude
|
|
|
|
* such cases here for safety.
|
1999-12-13 18:17:17 +03:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
if (ip6_forwarding || !ip6_accept_rtadv) {
|
|
|
|
nd6log((LOG_WARNING,
|
|
|
|
"defrouter_select: called unexpectedly (forwarding=%d, "
|
|
|
|
"accept_rtadv=%d)\n", ip6_forwarding, ip6_accept_rtadv));
|
|
|
|
splx(s);
|
|
|
|
return;
|
1999-12-13 18:17:17 +03:00
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* Let's handle easy case (3) first:
|
2004-10-26 10:54:53 +04:00
|
|
|
* If default router list is empty, there's nothing to be done.
|
2002-06-09 01:22:29 +04:00
|
|
|
*/
|
|
|
|
if (!TAILQ_FIRST(&nd_defrouter)) {
|
|
|
|
splx(s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Search for a (probably) reachable router from the list.
|
|
|
|
* We just pick up the first reachable one (if any), assuming that
|
|
|
|
* the ordering rule of the list described in defrtrlist_update().
|
|
|
|
*/
|
|
|
|
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
|
|
|
|
dr = TAILQ_NEXT(dr, dr_entry)) {
|
|
|
|
if (!selected_dr &&
|
|
|
|
(rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
|
|
|
|
(ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
|
|
|
|
ND6_IS_LLINFO_PROBREACH(ln)) {
|
|
|
|
selected_dr = dr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dr->installed && !installed_dr)
|
|
|
|
installed_dr = dr;
|
|
|
|
else if (dr->installed && installed_dr) {
|
|
|
|
/* this should not happen. warn for diagnosis. */
|
|
|
|
log(LOG_ERR, "defrouter_select: more than one router"
|
|
|
|
" is installed\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If none of the default routers was found to be reachable,
|
|
|
|
* round-robin the list regardless of preference.
|
|
|
|
* Otherwise, if we have an installed router, check if the selected
|
|
|
|
* (reachable) router should really be preferred to the installed one.
|
|
|
|
* We only prefer the new router when the old one is not reachable
|
|
|
|
* or when the new one has a really higher preference value.
|
|
|
|
*/
|
|
|
|
if (!selected_dr) {
|
|
|
|
if (!installed_dr || !TAILQ_NEXT(installed_dr, dr_entry))
|
|
|
|
selected_dr = TAILQ_FIRST(&nd_defrouter);
|
|
|
|
else
|
|
|
|
selected_dr = TAILQ_NEXT(installed_dr, dr_entry);
|
|
|
|
} else if (installed_dr &&
|
|
|
|
(rt = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) &&
|
|
|
|
(ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
|
|
|
|
ND6_IS_LLINFO_PROBREACH(ln) &&
|
|
|
|
rtpref(selected_dr) <= rtpref(installed_dr)) {
|
|
|
|
selected_dr = installed_dr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the selected router is different than the installed one,
|
|
|
|
* remove the installed router and install the selected one.
|
|
|
|
* Note that the selected router is never NULL here.
|
|
|
|
*/
|
|
|
|
if (installed_dr != selected_dr) {
|
|
|
|
if (installed_dr)
|
|
|
|
defrouter_delreq(installed_dr);
|
|
|
|
defrouter_addreq(selected_dr);
|
1999-12-13 18:17:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
splx(s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* for default router selection
|
|
|
|
* regards router-preference field as a 2-bit signed integer
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
rtpref(struct nd_defrouter *dr)
|
|
|
|
{
|
|
|
|
#ifdef RTPREF
|
|
|
|
switch (dr->flags & ND_RA_FLAG_RTPREF_MASK) {
|
|
|
|
case ND_RA_FLAG_RTPREF_HIGH:
|
|
|
|
return RTPREF_HIGH;
|
|
|
|
case ND_RA_FLAG_RTPREF_MEDIUM:
|
|
|
|
case ND_RA_FLAG_RTPREF_RSV:
|
|
|
|
return RTPREF_MEDIUM;
|
|
|
|
case ND_RA_FLAG_RTPREF_LOW:
|
|
|
|
return RTPREF_LOW;
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* This case should never happen. If it did, it would mean a
|
|
|
|
* serious bug of kernel internal. We thus always bark here.
|
|
|
|
* Or, can we even panic?
|
|
|
|
*/
|
|
|
|
log(LOG_ERR, "rtpref: impossible RA flag %x", dr->flags);
|
|
|
|
return RTPREF_INVALID;
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
static struct nd_defrouter *
|
|
|
|
defrtrlist_update(new)
|
|
|
|
struct nd_defrouter *new;
|
|
|
|
{
|
|
|
|
struct nd_defrouter *dr, *n;
|
1999-07-04 06:01:15 +04:00
|
|
|
int s = splsoftnet();
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) {
|
|
|
|
/* entry exists */
|
|
|
|
if (new->rtlifetime == 0) {
|
|
|
|
defrtrlist_del(dr);
|
|
|
|
dr = NULL;
|
|
|
|
} else {
|
2002-06-09 01:22:29 +04:00
|
|
|
int oldpref = rtpref(dr);
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/* override */
|
|
|
|
dr->flags = new->flags; /* xxx flag check */
|
|
|
|
dr->rtlifetime = new->rtlifetime;
|
|
|
|
dr->expire = new->expire;
|
2002-06-09 01:22:29 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If the preference does not change, there's no need
|
|
|
|
* to sort the entries.
|
|
|
|
*/
|
|
|
|
if (rtpref(new) == oldpref) {
|
|
|
|
splx(s);
|
2002-09-11 06:46:42 +04:00
|
|
|
return (dr);
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* preferred router may be changed, so relocate
|
|
|
|
* this router.
|
|
|
|
* XXX: calling TAILQ_REMOVE directly is a bad manner.
|
|
|
|
* However, since defrtrlist_del() has many side
|
|
|
|
* effects, we intentionally do so here.
|
|
|
|
* defrouter_select() below will handle routing
|
|
|
|
* changes later.
|
|
|
|
*/
|
|
|
|
TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
|
|
|
|
n = dr;
|
|
|
|
goto insert;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
splx(s);
|
2002-09-11 06:46:42 +04:00
|
|
|
return (dr);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* entry does not exist */
|
|
|
|
if (new->rtlifetime == 0) {
|
|
|
|
splx(s);
|
2002-09-11 06:46:42 +04:00
|
|
|
return (NULL);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
n = (struct nd_defrouter *)malloc(sizeof(*n), M_IP6NDP, M_NOWAIT);
|
|
|
|
if (n == NULL) {
|
|
|
|
splx(s);
|
2002-09-11 06:46:42 +04:00
|
|
|
return (NULL);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
bzero(n, sizeof(*n));
|
|
|
|
*n = *new;
|
1999-12-13 18:17:17 +03:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
insert:
|
1999-12-13 18:17:17 +03:00
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* Insert the new router in the Default Router List;
|
|
|
|
* The Default Router List should be in the descending order
|
|
|
|
* of router-preferece. Routers with the same preference are
|
|
|
|
* sorted in the arriving time order.
|
1999-12-13 18:17:17 +03:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
|
|
|
|
/* insert at the end of the group */
|
|
|
|
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
|
|
|
|
dr = TAILQ_NEXT(dr, dr_entry)) {
|
|
|
|
if (rtpref(n) > rtpref(dr))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (dr)
|
|
|
|
TAILQ_INSERT_BEFORE(dr, n, dr_entry);
|
|
|
|
else
|
|
|
|
TAILQ_INSERT_TAIL(&nd_defrouter, n, dr_entry);
|
|
|
|
|
|
|
|
defrouter_select();
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
splx(s);
|
2002-06-09 18:43:10 +04:00
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (n);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct nd_pfxrouter *
|
|
|
|
pfxrtr_lookup(pr, dr)
|
|
|
|
struct nd_prefix *pr;
|
|
|
|
struct nd_defrouter *dr;
|
|
|
|
{
|
|
|
|
struct nd_pfxrouter *search;
|
2002-06-09 18:43:10 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) {
|
|
|
|
if (search->router == dr)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (search);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pfxrtr_add(pr, dr)
|
|
|
|
struct nd_prefix *pr;
|
|
|
|
struct nd_defrouter *dr;
|
|
|
|
{
|
|
|
|
struct nd_pfxrouter *new;
|
|
|
|
|
|
|
|
new = (struct nd_pfxrouter *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
|
|
|
|
if (new == NULL)
|
|
|
|
return;
|
|
|
|
bzero(new, sizeof(*new));
|
|
|
|
new->router = dr;
|
|
|
|
|
|
|
|
LIST_INSERT_HEAD(&pr->ndpr_advrtrs, new, pfr_entry);
|
|
|
|
|
|
|
|
pfxlist_onlink_check();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pfxrtr_del(pfr)
|
|
|
|
struct nd_pfxrouter *pfr;
|
|
|
|
{
|
|
|
|
LIST_REMOVE(pfr, pfr_entry);
|
|
|
|
free(pfr, M_IP6NDP);
|
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
struct nd_prefix *
|
|
|
|
nd6_prefix_lookup(pr)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct nd_prefix *pr;
|
|
|
|
{
|
|
|
|
struct nd_prefix *search;
|
|
|
|
|
|
|
|
for (search = nd_prefix.lh_first; search; search = search->ndpr_next) {
|
|
|
|
if (pr->ndpr_ifp == search->ndpr_ifp &&
|
|
|
|
pr->ndpr_plen == search->ndpr_plen &&
|
|
|
|
in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
|
2002-06-09 01:22:29 +04:00
|
|
|
&search->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (search);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
int
|
|
|
|
nd6_prelist_add(pr, dr, newp)
|
|
|
|
struct nd_prefix *pr, **newp;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct nd_defrouter *dr;
|
|
|
|
{
|
2002-06-09 01:22:29 +04:00
|
|
|
struct nd_prefix *new = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
int i, s;
|
|
|
|
|
|
|
|
new = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT);
|
|
|
|
if (new == NULL)
|
|
|
|
return ENOMEM;
|
|
|
|
bzero(new, sizeof(*new));
|
|
|
|
*new = *pr;
|
2002-06-09 01:22:29 +04:00
|
|
|
if (newp != NULL)
|
|
|
|
*newp = new;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* initilization */
|
|
|
|
LIST_INIT(&new->ndpr_advrtrs);
|
|
|
|
in6_prefixlen2mask(&new->ndpr_mask, new->ndpr_plen);
|
|
|
|
/* make prefix in the canonical form */
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
new->ndpr_prefix.sin6_addr.s6_addr32[i] &=
|
2002-06-09 01:22:29 +04:00
|
|
|
new->ndpr_mask.s6_addr32[i];
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1999-07-04 06:01:15 +04:00
|
|
|
s = splsoftnet();
|
1999-06-28 10:36:47 +04:00
|
|
|
/* link ndpr_entry to nd_prefix list */
|
|
|
|
LIST_INSERT_HEAD(&nd_prefix, new, ndpr_entry);
|
|
|
|
splx(s);
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* ND_OPT_PI_FLAG_ONLINK processing */
|
|
|
|
if (new->ndpr_raf_onlink) {
|
|
|
|
int e;
|
|
|
|
|
|
|
|
if ((e = nd6_prefix_onlink(new)) != 0) {
|
|
|
|
nd6log((LOG_ERR, "nd6_prelist_add: failed to make "
|
|
|
|
"the prefix %s/%d on-link on %s (errno=%d)\n",
|
|
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
|
|
|
pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
|
|
|
|
/* proceed anyway. XXX: is it correct? */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
if (dr)
|
|
|
|
pfxrtr_add(new, dr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
prelist_remove(pr)
|
|
|
|
struct nd_prefix *pr;
|
|
|
|
{
|
|
|
|
struct nd_pfxrouter *pfr, *next;
|
2002-06-09 01:22:29 +04:00
|
|
|
int e, s;
|
|
|
|
|
|
|
|
/* make sure to invalidate the prefix until it is really freed. */
|
|
|
|
pr->ndpr_vltime = 0;
|
|
|
|
pr->ndpr_pltime = 0;
|
|
|
|
#if 0
|
|
|
|
/*
|
|
|
|
* Though these flags are now meaningless, we'd rather keep the value
|
|
|
|
* not to confuse users when executing "ndp -p".
|
|
|
|
*/
|
|
|
|
pr->ndpr_raf_onlink = 0;
|
|
|
|
pr->ndpr_raf_auto = 0;
|
|
|
|
#endif
|
|
|
|
if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0 &&
|
|
|
|
(e = nd6_prefix_offlink(pr)) != 0) {
|
|
|
|
nd6log((LOG_ERR, "prelist_remove: failed to make %s/%d offlink "
|
|
|
|
"on %s, errno=%d\n",
|
|
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
|
|
|
pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
|
|
|
|
/* what should we do? */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pr->ndpr_refcnt > 0)
|
|
|
|
return; /* notice here? */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1999-07-04 06:01:15 +04:00
|
|
|
s = splsoftnet();
|
1999-06-28 10:36:47 +04:00
|
|
|
/* unlink ndpr_entry from nd_prefix list */
|
|
|
|
LIST_REMOVE(pr, ndpr_entry);
|
|
|
|
|
|
|
|
/* free list of routers that adversed the prefix */
|
|
|
|
for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) {
|
|
|
|
next = pfr->pfr_next;
|
|
|
|
|
|
|
|
free(pfr, M_IP6NDP);
|
|
|
|
}
|
2001-02-11 10:12:01 +03:00
|
|
|
splx(s);
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
free(pr, M_IP6NDP);
|
|
|
|
|
|
|
|
pfxlist_onlink_check();
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
prelist_update(new, dr, m)
|
|
|
|
struct nd_prefix *new;
|
|
|
|
struct nd_defrouter *dr; /* may be NULL */
|
|
|
|
struct mbuf *m;
|
|
|
|
{
|
2002-06-09 01:22:29 +04:00
|
|
|
struct in6_ifaddr *ia6 = NULL, *ia6_match = NULL;
|
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct ifnet *ifp = new->ndpr_ifp;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct nd_prefix *pr;
|
1999-07-04 06:01:15 +04:00
|
|
|
int s = splsoftnet();
|
1999-06-28 10:36:47 +04:00
|
|
|
int error = 0;
|
|
|
|
int auth;
|
2002-06-09 01:22:29 +04:00
|
|
|
struct in6_addrlifetime lt6_tmp;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
auth = 0;
|
1999-06-28 10:36:47 +04:00
|
|
|
if (m) {
|
|
|
|
/*
|
|
|
|
* Authenticity for NA consists authentication for
|
|
|
|
* both IP header and IP datagrams, doesn't it ?
|
|
|
|
*/
|
1999-12-13 18:17:17 +03:00
|
|
|
#if defined(M_AUTHIPHDR) && defined(M_AUTHIPDGM)
|
1999-06-28 10:36:47 +04:00
|
|
|
auth = (m->m_flags & M_AUTHIPHDR
|
|
|
|
&& m->m_flags & M_AUTHIPDGM) ? 1 : 0;
|
1999-12-13 18:17:17 +03:00
|
|
|
#endif
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
if ((pr = nd6_prefix_lookup(new)) != NULL) {
|
|
|
|
/*
|
|
|
|
* nd6_prefix_lookup() ensures that pr and new have the same
|
|
|
|
* prefix on a same interface.
|
|
|
|
*/
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* Update prefix information. Note that the on-link (L) bit
|
|
|
|
* and the autonomous (A) bit should NOT be changed from 1
|
|
|
|
* to 0.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
if (new->ndpr_raf_onlink == 1)
|
|
|
|
pr->ndpr_raf_onlink = 1;
|
|
|
|
if (new->ndpr_raf_auto == 1)
|
|
|
|
pr->ndpr_raf_auto = 1;
|
|
|
|
if (new->ndpr_raf_onlink) {
|
|
|
|
pr->ndpr_vltime = new->ndpr_vltime;
|
|
|
|
pr->ndpr_pltime = new->ndpr_pltime;
|
|
|
|
pr->ndpr_preferred = new->ndpr_preferred;
|
|
|
|
pr->ndpr_expire = new->ndpr_expire;
|
|
|
|
pr->ndpr_lastupdate = new->ndpr_lastupdate;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
if (new->ndpr_raf_onlink &&
|
|
|
|
(pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
|
|
|
|
int e;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
if ((e = nd6_prefix_onlink(pr)) != 0) {
|
2001-04-04 10:28:41 +04:00
|
|
|
nd6log((LOG_ERR,
|
2002-06-09 01:22:29 +04:00
|
|
|
"prelist_update: failed to make "
|
|
|
|
"the prefix %s/%d on-link on %s "
|
|
|
|
"(errno=%d)\n",
|
|
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
|
|
|
pr->ndpr_plen, if_name(pr->ndpr_ifp), e));
|
|
|
|
/* proceed anyway. XXX: is it correct? */
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
if (dr && pfxrtr_lookup(pr, dr) == NULL)
|
|
|
|
pfxrtr_add(pr, dr);
|
|
|
|
} else {
|
|
|
|
struct nd_prefix *newpr = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
if (new->ndpr_vltime == 0)
|
|
|
|
goto end;
|
|
|
|
if (new->ndpr_raf_onlink == 0 && new->ndpr_raf_auto == 0)
|
|
|
|
goto end;
|
1999-12-13 18:17:17 +03:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
error = nd6_prelist_add(new, dr, &newpr);
|
|
|
|
if (error != 0 || newpr == NULL) {
|
|
|
|
nd6log((LOG_NOTICE, "prelist_update: "
|
|
|
|
"nd6_prelist_add failed for %s/%d on %s "
|
|
|
|
"errno=%d, returnpr=%p\n",
|
|
|
|
ip6_sprintf(&new->ndpr_prefix.sin6_addr),
|
|
|
|
new->ndpr_plen, if_name(new->ndpr_ifp),
|
|
|
|
error, newpr));
|
|
|
|
goto end; /* we should just give up in this case. */
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* XXX: from the ND point of view, we can ignore a prefix
|
|
|
|
* with the on-link bit being zero. However, we need a
|
|
|
|
* prefix structure for references from autoconfigured
|
|
|
|
* addresses. Thus, we explicitly make sure that the prefix
|
|
|
|
* itself expires now.
|
|
|
|
*/
|
|
|
|
if (newpr->ndpr_raf_onlink == 0) {
|
|
|
|
newpr->ndpr_vltime = 0;
|
|
|
|
newpr->ndpr_pltime = 0;
|
|
|
|
in6_init_prefix_ltimes(newpr);
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
pr = newpr;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* Address autoconfiguration based on Section 5.5.3 of RFC 2462.
|
|
|
|
* Note that pr must be non NULL at this point.
|
|
|
|
*/
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* 5.5.3 (a). Ignore the prefix without the A bit set. */
|
|
|
|
if (!new->ndpr_raf_auto)
|
|
|
|
goto end;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* 5.5.3 (b). the link-local prefix should have been ignored in
|
|
|
|
* nd6_ra_input.
|
|
|
|
*/
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* 5.5.3 (c). Consistency check on lifetimes: pltime <= vltime.
|
|
|
|
* This should have been done in nd6_ra_input.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 5.5.3 (d). If the prefix advertised does not match the prefix of an
|
|
|
|
* address already in the list, and the Valid Lifetime is not 0,
|
|
|
|
* form an address. Note that even a manually configured address
|
|
|
|
* should reject autoconfiguration of a new address.
|
|
|
|
*/
|
|
|
|
for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next)
|
|
|
|
{
|
|
|
|
struct in6_ifaddr *ifa6;
|
|
|
|
int ifa_plen;
|
|
|
|
u_int32_t storedlifetime;
|
|
|
|
|
|
|
|
if (ifa->ifa_addr->sa_family != AF_INET6)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ifa6 = (struct in6_ifaddr *)ifa;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* Spec is not clear here, but I believe we should concentrate
|
|
|
|
* on unicast (i.e. not anycast) addresses.
|
|
|
|
* XXX: other ia6_flags? detached or duplicated?
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
if ((ifa6->ia6_flags & IN6_IFF_ANYCAST) != 0)
|
|
|
|
continue;
|
2002-06-09 18:43:10 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
ifa_plen = in6_mask2len(&ifa6->ia_prefixmask.sin6_addr, NULL);
|
|
|
|
if (ifa_plen != new->ndpr_plen ||
|
|
|
|
!in6_are_prefix_equal(&ifa6->ia_addr.sin6_addr,
|
|
|
|
&new->ndpr_prefix.sin6_addr, ifa_plen))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ia6_match == NULL) /* remember the first one */
|
|
|
|
ia6_match = ifa6;
|
|
|
|
|
|
|
|
if ((ifa6->ia6_flags & IN6_IFF_AUTOCONF) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* An already autoconfigured address matched. Now that we
|
|
|
|
* are sure there is at least one matched address, we can
|
|
|
|
* proceed to 5.5.3. (e): update the lifetimes according to the
|
|
|
|
* "two hours" rule and the privacy extension.
|
|
|
|
*/
|
|
|
|
#define TWOHOUR (120*60)
|
|
|
|
/*
|
|
|
|
* RFC2462 introduces the notion of StoredLifetime to the
|
|
|
|
* "two hours" rule as follows:
|
|
|
|
* the Lifetime associated with the previously autoconfigured
|
|
|
|
* address.
|
|
|
|
* Our interpretation of this definition is "the remaining
|
|
|
|
* lifetime to expiration at the evaluation time". One might
|
|
|
|
* be wondering if this interpretation is really conform to the
|
|
|
|
* RFC, because the text can read that "Lifetimes" are never
|
|
|
|
* decreased, and our definition of the "storedlifetime" below
|
|
|
|
* essentially reduces the "Valid Lifetime" advertised in the
|
|
|
|
* previous RA. But, this is due to the wording of the text,
|
|
|
|
* and our interpretation is the same as an author's intention.
|
|
|
|
* See the discussion in the IETF ipngwg ML in August 2001,
|
|
|
|
* with the Subject "StoredLifetime in RFC 2462".
|
|
|
|
*/
|
|
|
|
lt6_tmp = ifa6->ia6_lifetime;
|
|
|
|
if (lt6_tmp.ia6t_vltime == ND6_INFINITE_LIFETIME)
|
|
|
|
storedlifetime = ND6_INFINITE_LIFETIME;
|
2003-06-24 11:39:24 +04:00
|
|
|
else if (time.tv_sec - ifa6->ia6_updatetime >
|
2002-06-09 01:22:29 +04:00
|
|
|
lt6_tmp.ia6t_vltime) {
|
|
|
|
/*
|
|
|
|
* The case of "invalid" address. We should usually
|
|
|
|
* not see this case.
|
|
|
|
*/
|
|
|
|
storedlifetime = 0;
|
|
|
|
} else
|
|
|
|
storedlifetime = lt6_tmp.ia6t_vltime -
|
2003-06-24 11:39:24 +04:00
|
|
|
(time.tv_sec - ifa6->ia6_updatetime);
|
2002-06-09 01:22:29 +04:00
|
|
|
if (TWOHOUR < new->ndpr_vltime ||
|
|
|
|
storedlifetime < new->ndpr_vltime) {
|
|
|
|
lt6_tmp.ia6t_vltime = new->ndpr_vltime;
|
|
|
|
} else if (storedlifetime <= TWOHOUR
|
|
|
|
#if 0
|
|
|
|
/*
|
|
|
|
* This condition is logically redundant, so we just
|
|
|
|
* omit it.
|
|
|
|
* See IPng 6712, 6717, and 6721.
|
|
|
|
*/
|
|
|
|
&& new->ndpr_vltime <= storedlifetime
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
if (auth) {
|
|
|
|
lt6_tmp.ia6t_vltime = new->ndpr_vltime;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* new->ndpr_vltime <= TWOHOUR &&
|
|
|
|
* TWOHOUR < storedlifetime
|
|
|
|
*/
|
|
|
|
lt6_tmp.ia6t_vltime = TWOHOUR;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* The 2 hour rule is not imposed for preferred lifetime. */
|
|
|
|
lt6_tmp.ia6t_pltime = new->ndpr_pltime;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
in6_init_address_ltimes(pr, <6_tmp);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
ifa6->ia6_lifetime = lt6_tmp;
|
2003-06-24 11:39:24 +04:00
|
|
|
ifa6->ia6_updatetime = time.tv_sec;
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
|
|
|
if (ia6_match == NULL && new->ndpr_vltime) {
|
|
|
|
/*
|
|
|
|
* No address matched and the valid lifetime is non-zero.
|
|
|
|
* Create a new address.
|
|
|
|
*/
|
|
|
|
if ((ia6 = in6_ifadd(new)) != NULL) {
|
|
|
|
/*
|
|
|
|
* note that we should use pr (not new) for reference.
|
|
|
|
*/
|
|
|
|
pr->ndpr_refcnt++;
|
|
|
|
ia6->ia6_ndpr = pr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A newly added address might affect the status
|
|
|
|
* of other addresses, so we check and update it.
|
|
|
|
* XXX: what if address duplication happens?
|
|
|
|
*/
|
|
|
|
pfxlist_onlink_check();
|
|
|
|
} else {
|
|
|
|
/* just set an error. do not bark here. */
|
|
|
|
error = EADDRNOTAVAIL; /* XXX: might be unused. */
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
|
|
|
splx(s);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
/*
|
|
|
|
* A supplement function used in the on-link detection below;
|
|
|
|
* detect if a given prefix has a (probably) reachable advertising router.
|
|
|
|
* XXX: lengthy function name...
|
|
|
|
*/
|
|
|
|
static struct nd_pfxrouter *
|
|
|
|
find_pfxlist_reachable_router(pr)
|
|
|
|
struct nd_prefix *pr;
|
|
|
|
{
|
|
|
|
struct nd_pfxrouter *pfxrtr;
|
|
|
|
struct rtentry *rt;
|
|
|
|
struct llinfo_nd6 *ln;
|
|
|
|
|
|
|
|
for (pfxrtr = LIST_FIRST(&pr->ndpr_advrtrs); pfxrtr;
|
|
|
|
pfxrtr = LIST_NEXT(pfxrtr, pfr_entry)) {
|
|
|
|
if ((rt = nd6_lookup(&pfxrtr->router->rtaddr, 0,
|
2002-06-09 01:22:29 +04:00
|
|
|
pfxrtr->router->ifp)) &&
|
1999-12-13 18:17:17 +03:00
|
|
|
(ln = (struct llinfo_nd6 *)rt->rt_llinfo) &&
|
|
|
|
ND6_IS_LLINFO_PROBREACH(ln))
|
|
|
|
break; /* found */
|
|
|
|
}
|
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (pfxrtr);
|
1999-12-13 18:17:17 +03:00
|
|
|
}
|
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* Check if each prefix in the prefix list has at least one available router
|
2001-10-16 10:24:44 +04:00
|
|
|
* that advertised the prefix (a router is "available" if its neighbor cache
|
|
|
|
* entry is reachable or probably reachable).
|
1999-12-13 18:17:17 +03:00
|
|
|
* If the check fails, the prefix may be off-link, because, for example,
|
1999-06-28 10:36:47 +04:00
|
|
|
* we have moved from the network but the lifetime of the prefix has not
|
2001-10-16 10:24:44 +04:00
|
|
|
* expired yet. So we should not use the prefix if there is another prefix
|
|
|
|
* that has an available router.
|
|
|
|
* But, if there is no prefix that has an available router, we still regards
|
|
|
|
* all the prefixes as on-link. This is because we can't tell if all the
|
1999-06-28 10:36:47 +04:00
|
|
|
* routers are simply dead or if we really moved from the network and there
|
|
|
|
* is no router around us.
|
|
|
|
*/
|
1999-12-13 18:17:17 +03:00
|
|
|
void
|
1999-06-28 10:36:47 +04:00
|
|
|
pfxlist_onlink_check()
|
|
|
|
{
|
|
|
|
struct nd_prefix *pr;
|
2002-06-09 01:22:29 +04:00
|
|
|
struct in6_ifaddr *ifa;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
1999-12-13 18:17:17 +03:00
|
|
|
/*
|
|
|
|
* Check if there is a prefix that has a reachable advertising
|
|
|
|
* router.
|
|
|
|
*/
|
|
|
|
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
|
2002-06-09 01:22:29 +04:00
|
|
|
if (pr->ndpr_raf_onlink && find_pfxlist_reachable_router(pr))
|
1999-06-28 10:36:47 +04:00
|
|
|
break;
|
1999-12-13 18:17:17 +03:00
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
if (pr != NULL || TAILQ_FIRST(&nd_defrouter) != NULL) {
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* There is at least one prefix that has a reachable router,
|
|
|
|
* or at least a router which probably does not advertise
|
|
|
|
* any prefixes. The latter would be the case when we move
|
|
|
|
* to a new link where we have a router that does not provide
|
|
|
|
* prefixes and we configure an address by hand.
|
|
|
|
* Detach prefixes which have no reachable advertising
|
|
|
|
* router, and attach other prefixes.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
|
2002-06-09 01:22:29 +04:00
|
|
|
/* XXX: a link-local prefix should never be detached */
|
|
|
|
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we aren't interested in prefixes without the L bit
|
|
|
|
* set.
|
|
|
|
*/
|
|
|
|
if (pr->ndpr_raf_onlink == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
|
|
|
|
find_pfxlist_reachable_router(pr) == NULL)
|
|
|
|
pr->ndpr_stateflags |= NDPRF_DETACHED;
|
|
|
|
if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
|
|
|
|
find_pfxlist_reachable_router(pr) != 0)
|
|
|
|
pr->ndpr_stateflags &= ~NDPRF_DETACHED;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
} else {
|
|
|
|
/* there is no prefix that has a reachable router */
|
1999-06-28 10:36:47 +04:00
|
|
|
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
|
2002-06-09 01:22:29 +04:00
|
|
|
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (pr->ndpr_raf_onlink == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0)
|
|
|
|
pr->ndpr_stateflags &= ~NDPRF_DETACHED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove each interface route associated with a (just) detached
|
|
|
|
* prefix, and reinstall the interface route for a (just) attached
|
|
|
|
* prefix. Note that all attempt of reinstallation does not
|
|
|
|
* necessarily success, when a same prefix is shared among multiple
|
|
|
|
* interfaces. Such cases will be handled in nd6_prefix_onlink,
|
|
|
|
* so we don't have to care about them.
|
|
|
|
*/
|
|
|
|
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
|
|
|
|
int e;
|
|
|
|
|
|
|
|
if (IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (pr->ndpr_raf_onlink == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((pr->ndpr_stateflags & NDPRF_DETACHED) != 0 &&
|
|
|
|
(pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
|
|
|
|
if ((e = nd6_prefix_offlink(pr)) != 0) {
|
|
|
|
nd6log((LOG_ERR,
|
|
|
|
"pfxlist_onlink_check: failed to "
|
|
|
|
"make %s/%d offlink, errno=%d\n",
|
|
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
|
|
|
pr->ndpr_plen, e));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
|
|
|
|
(pr->ndpr_stateflags & NDPRF_ONLINK) == 0 &&
|
|
|
|
pr->ndpr_raf_onlink) {
|
|
|
|
if ((e = nd6_prefix_onlink(pr)) != 0) {
|
|
|
|
nd6log((LOG_ERR,
|
|
|
|
"pfxlist_onlink_check: failed to "
|
|
|
|
"make %s/%d offlink, errno=%d\n",
|
|
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
|
|
|
pr->ndpr_plen, e));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Changes on the prefix status might affect address status as well.
|
|
|
|
* Make sure that all addresses derived from an attached prefix are
|
|
|
|
* attached, and that all addresses derived from a detached prefix are
|
|
|
|
* detached. Note, however, that a manually configured address should
|
|
|
|
* always be attached.
|
|
|
|
* The precise detection logic is same as the one for prefixes.
|
|
|
|
*/
|
|
|
|
for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
|
|
|
|
if (!(ifa->ia6_flags & IN6_IFF_AUTOCONF))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ifa->ia6_ndpr == NULL) {
|
|
|
|
/*
|
|
|
|
* This can happen when we first configure the address
|
|
|
|
* (i.e. the address exists, but the prefix does not).
|
|
|
|
* XXX: complicated relationships...
|
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ifa) {
|
|
|
|
for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
|
|
|
|
if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ifa->ia6_ndpr == NULL) /* XXX: see above. */
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (find_pfxlist_reachable_router(ifa->ia6_ndpr))
|
|
|
|
ifa->ia6_flags &= ~IN6_IFF_DETACHED;
|
|
|
|
else
|
|
|
|
ifa->ia6_flags |= IN6_IFF_DETACHED;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2002-06-09 01:22:29 +04:00
|
|
|
for (ifa = in6_ifaddr; ifa; ifa = ifa->ia_next) {
|
|
|
|
if ((ifa->ia6_flags & IN6_IFF_AUTOCONF) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ifa->ia6_flags &= ~IN6_IFF_DETACHED;
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
int
|
|
|
|
nd6_prefix_onlink(pr)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct nd_prefix *pr;
|
|
|
|
{
|
2002-06-09 01:22:29 +04:00
|
|
|
struct ifaddr *ifa;
|
|
|
|
struct ifnet *ifp = pr->ndpr_ifp;
|
|
|
|
struct sockaddr_in6 mask6;
|
|
|
|
struct nd_prefix *opr;
|
|
|
|
u_long rtflags;
|
|
|
|
int error = 0;
|
|
|
|
struct rtentry *rt = NULL;
|
|
|
|
|
|
|
|
/* sanity check */
|
|
|
|
if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
|
|
|
|
nd6log((LOG_ERR,
|
|
|
|
"nd6_prefix_onlink: %s/%d is already on-link\n",
|
2004-11-17 06:20:53 +03:00
|
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen));
|
|
|
|
return (EEXIST);
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* Add the interface route associated with the prefix. Before
|
|
|
|
* installing the route, check if there's the same prefix on another
|
|
|
|
* interface, and the prefix has already installed the interface route.
|
|
|
|
* Although such a configuration is expected to be rare, we explicitly
|
|
|
|
* allow it.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
|
|
|
|
if (opr == pr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (opr->ndpr_plen == pr->ndpr_plen &&
|
|
|
|
in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
|
|
|
|
&opr->ndpr_prefix.sin6_addr, pr->ndpr_plen))
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* We prefer link-local addresses as the associated interface address.
|
|
|
|
*/
|
|
|
|
/* search for a link-local addr */
|
|
|
|
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
|
|
|
|
IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
|
|
|
|
if (ifa == NULL) {
|
|
|
|
/* XXX: freebsd does not have ifa_ifwithaf */
|
|
|
|
for (ifa = ifp->if_addrlist.tqh_first;
|
|
|
|
ifa;
|
|
|
|
ifa = ifa->ifa_list.tqe_next)
|
|
|
|
{
|
|
|
|
if (ifa->ifa_addr->sa_family == AF_INET6)
|
|
|
|
break;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
/* should we care about ia6_flags? */
|
|
|
|
}
|
|
|
|
if (ifa == NULL) {
|
|
|
|
/*
|
|
|
|
* This can still happen, when, for example, we receive an RA
|
|
|
|
* containing a prefix with the L bit set and the A bit clear,
|
|
|
|
* after removing all IPv6 addresses on the receiving
|
|
|
|
* interface. This should, of course, be rare though.
|
|
|
|
*/
|
|
|
|
nd6log((LOG_NOTICE,
|
|
|
|
"nd6_prefix_onlink: failed to find any ifaddr"
|
|
|
|
" to add route for a prefix(%s/%d) on %s\n",
|
|
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
|
|
|
pr->ndpr_plen, if_name(ifp)));
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
|
|
|
|
* ifa->ifa_rtrequest = nd6_rtrequest;
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
bzero(&mask6, sizeof(mask6));
|
|
|
|
mask6.sin6_len = sizeof(mask6);
|
|
|
|
mask6.sin6_addr = pr->ndpr_mask;
|
|
|
|
/* rtrequest() will probably set RTF_UP, but we're not sure. */
|
|
|
|
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;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* explicitly clear the cloning bit in case ifa_flags sets it.
|
|
|
|
*/
|
|
|
|
rtflags &= ~RTF_CLONING;
|
|
|
|
}
|
|
|
|
error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
|
|
|
|
ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt);
|
|
|
|
if (error == 0) {
|
|
|
|
if (rt != NULL) /* this should be non NULL, though */
|
|
|
|
nd6_rtmsg(RTM_ADD, rt);
|
|
|
|
pr->ndpr_stateflags |= NDPRF_ONLINK;
|
|
|
|
} else {
|
|
|
|
nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a"
|
|
|
|
" prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx "
|
|
|
|
"errno = %d\n",
|
|
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
|
|
|
|
pr->ndpr_plen, if_name(ifp),
|
|
|
|
ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
|
|
|
|
ip6_sprintf(&mask6.sin6_addr), rtflags, error));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rt != NULL)
|
|
|
|
rt->rt_refcnt--;
|
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (error);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
int
|
|
|
|
nd6_prefix_offlink(pr)
|
1999-06-28 10:36:47 +04:00
|
|
|
struct nd_prefix *pr;
|
|
|
|
{
|
2002-06-09 01:22:29 +04:00
|
|
|
int error = 0;
|
|
|
|
struct ifnet *ifp = pr->ndpr_ifp;
|
|
|
|
struct nd_prefix *opr;
|
|
|
|
struct sockaddr_in6 sa6, mask6;
|
|
|
|
struct rtentry *rt = NULL;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* sanity check */
|
|
|
|
if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
|
2001-04-04 10:28:41 +04:00
|
|
|
nd6log((LOG_ERR,
|
2002-06-09 01:22:29 +04:00
|
|
|
"nd6_prefix_offlink: %s/%d is already off-link\n",
|
|
|
|
ip6_sprintf(&pr->ndpr_prefix.sin6_addr), pr->ndpr_plen));
|
2002-09-11 06:46:42 +04:00
|
|
|
return (EEXIST);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
|
|
|
|
bzero(&sa6, sizeof(sa6));
|
|
|
|
sa6.sin6_family = AF_INET6;
|
|
|
|
sa6.sin6_len = sizeof(sa6);
|
|
|
|
bcopy(&pr->ndpr_prefix.sin6_addr, &sa6.sin6_addr,
|
|
|
|
sizeof(struct in6_addr));
|
|
|
|
bzero(&mask6, sizeof(mask6));
|
|
|
|
mask6.sin6_family = AF_INET6;
|
|
|
|
mask6.sin6_len = sizeof(sa6);
|
|
|
|
bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
|
|
|
|
error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
|
|
|
|
(struct sockaddr *)&mask6, 0, &rt);
|
|
|
|
if (error == 0) {
|
|
|
|
pr->ndpr_stateflags &= ~NDPRF_ONLINK;
|
|
|
|
|
|
|
|
/* report the route deletion to the routing socket. */
|
|
|
|
if (rt != NULL)
|
|
|
|
nd6_rtmsg(RTM_DELETE, rt);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There might be the same prefix on another interface,
|
|
|
|
* the prefix which could not be on-link just because we have
|
|
|
|
* the interface route (see comments in nd6_prefix_onlink).
|
|
|
|
* If there's one, try to make the prefix on-link on the
|
|
|
|
* interface.
|
|
|
|
*/
|
|
|
|
for (opr = nd_prefix.lh_first; opr; opr = opr->ndpr_next) {
|
|
|
|
if (opr == pr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((opr->ndpr_stateflags & NDPRF_ONLINK) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* KAME specific: detached prefixes should not be
|
|
|
|
* on-link.
|
|
|
|
*/
|
|
|
|
if ((opr->ndpr_stateflags & NDPRF_DETACHED) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (opr->ndpr_plen == pr->ndpr_plen &&
|
|
|
|
in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
|
|
|
|
&opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
|
|
|
|
int e;
|
|
|
|
|
|
|
|
if ((e = nd6_prefix_onlink(opr)) != 0) {
|
|
|
|
nd6log((LOG_ERR,
|
|
|
|
"nd6_prefix_offlink: failed to "
|
|
|
|
"recover a prefix %s/%d from %s "
|
|
|
|
"to %s (errno = %d)\n",
|
|
|
|
ip6_sprintf(&opr->ndpr_prefix.sin6_addr),
|
|
|
|
opr->ndpr_plen, if_name(ifp),
|
|
|
|
if_name(opr->ndpr_ifp), e));
|
|
|
|
}
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
} else {
|
|
|
|
/* XXX: can we still set the NDPRF_ONLINK flag? */
|
|
|
|
nd6log((LOG_ERR,
|
|
|
|
"nd6_prefix_offlink: failed to delete route: "
|
|
|
|
"%s/%d on %s (errno = %d)\n",
|
|
|
|
ip6_sprintf(&sa6.sin6_addr), pr->ndpr_plen, if_name(ifp),
|
|
|
|
error));
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
if (rt != NULL) {
|
|
|
|
if (rt->rt_refcnt <= 0) {
|
|
|
|
/* XXX: we should free the entry ourselves. */
|
|
|
|
rt->rt_refcnt++;
|
|
|
|
rtfree(rt);
|
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
2002-06-09 01:22:29 +04:00
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (error);
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct in6_ifaddr *
|
2002-06-09 01:22:29 +04:00
|
|
|
in6_ifadd(pr)
|
|
|
|
struct nd_prefix *pr;
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
2002-06-09 01:22:29 +04:00
|
|
|
struct ifnet *ifp = pr->ndpr_ifp;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct ifaddr *ifa;
|
2002-06-09 01:22:29 +04:00
|
|
|
struct in6_aliasreq ifra;
|
|
|
|
struct in6_ifaddr *ia, *ib;
|
|
|
|
int error, plen0;
|
1999-06-28 10:36:47 +04:00
|
|
|
struct in6_addr mask;
|
2002-06-09 01:22:29 +04:00
|
|
|
int prefixlen = pr->ndpr_plen;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-08 04:07:00 +04:00
|
|
|
in6_prefixlen2mask(&mask, prefixlen);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/*
|
|
|
|
* find a link-local address (will be interface ID).
|
|
|
|
* Is it really mandatory? Theoretically, a global or a site-local
|
|
|
|
* address can be configured without a link-local address, if we
|
|
|
|
* have a unique interface identifier...
|
|
|
|
*
|
|
|
|
* it is not mandatory to have a link-local address, we can generate
|
|
|
|
* interface identifier on the fly. we do this because:
|
|
|
|
* (1) it should be the easiest way to find interface identifier.
|
|
|
|
* (2) RFC2462 5.4 suggesting the use of the same interface identifier
|
|
|
|
* for multiple addresses on a single interface, and possible shortcut
|
|
|
|
* of DAD. we omitted DAD for this reason in the past.
|
|
|
|
* (3) a user can prevent autoconfiguration of global address
|
|
|
|
* by removing link-local address by hand (this is partly because we
|
|
|
|
* don't have other way to control the use of IPv6 on a interface.
|
|
|
|
* this has been our design choice - cf. NRL's "ifconfig auto").
|
|
|
|
* (4) it is easier to manage when an interface has addresses
|
|
|
|
* with the same interface identifier, than to have multiple addresses
|
|
|
|
* with different interface identifiers.
|
|
|
|
*/
|
|
|
|
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */
|
1999-06-28 10:36:47 +04:00
|
|
|
if (ifa)
|
|
|
|
ib = (struct in6_ifaddr *)ifa;
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
#if 0 /* don't care link local addr state, and always do DAD */
|
|
|
|
/* if link-local address is not eligible, do not autoconfigure. */
|
|
|
|
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) {
|
|
|
|
printf("in6_ifadd: link-local address not ready\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* prefixlen + ifidlen must be equal to 128 */
|
2002-06-09 01:22:29 +04:00
|
|
|
plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL);
|
|
|
|
if (prefixlen != plen0) {
|
2001-04-04 10:28:41 +04:00
|
|
|
nd6log((LOG_ERR, "in6_ifadd: wrong prefixlen for %s"
|
2002-06-09 01:22:29 +04:00
|
|
|
"(prefix=%d ifid=%d)\n",
|
|
|
|
if_name(ifp), prefixlen, 128 - plen0));
|
1999-06-28 10:36:47 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make ifaddr */
|
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
bzero(&ifra, sizeof(ifra));
|
|
|
|
/*
|
|
|
|
* in6_update_ifa() does not use ifra_name, but we accurately set it
|
|
|
|
* for safety.
|
|
|
|
*/
|
|
|
|
strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
|
|
|
|
ifra.ifra_addr.sin6_family = AF_INET6;
|
|
|
|
ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
|
1999-06-28 10:36:47 +04:00
|
|
|
/* prefix */
|
2002-06-09 01:22:29 +04:00
|
|
|
bcopy(&pr->ndpr_prefix.sin6_addr, &ifra.ifra_addr.sin6_addr,
|
|
|
|
sizeof(ifra.ifra_addr.sin6_addr));
|
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[0] &= mask.s6_addr32[0];
|
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[1] &= mask.s6_addr32[1];
|
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[2] &= mask.s6_addr32[2];
|
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[3] &= mask.s6_addr32[3];
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* interface ID */
|
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[0] |=
|
|
|
|
(ib->ia_addr.sin6_addr.s6_addr32[0] & ~mask.s6_addr32[0]);
|
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[1] |=
|
|
|
|
(ib->ia_addr.sin6_addr.s6_addr32[1] & ~mask.s6_addr32[1]);
|
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[2] |=
|
|
|
|
(ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
|
|
|
|
ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
|
|
|
|
(ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
|
2002-06-09 18:43:10 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* new prefix mask. */
|
|
|
|
ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
ifra.ifra_prefixmask.sin6_family = AF_INET6;
|
|
|
|
bcopy(&mask, &ifra.ifra_prefixmask.sin6_addr,
|
|
|
|
sizeof(ifra.ifra_prefixmask.sin6_addr));
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/*
|
2002-06-09 01:22:29 +04:00
|
|
|
* lifetime.
|
|
|
|
* XXX: in6_init_address_ltimes would override these values later.
|
|
|
|
* We should reconsider this logic.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
2002-06-09 01:22:29 +04:00
|
|
|
ifra.ifra_lifetime.ia6t_vltime = pr->ndpr_vltime;
|
|
|
|
ifra.ifra_lifetime.ia6t_pltime = pr->ndpr_pltime;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* XXX: scope zone ID? */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
ifra.ifra_flags |= IN6_IFF_AUTOCONF; /* obey autoconf */
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
/* allocate ifaddr structure, link into chain, etc. */
|
|
|
|
if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
|
|
|
|
nd6log((LOG_ERR,
|
|
|
|
"in6_ifadd: failed to make ifaddr %s on %s (errno=%d)\n",
|
|
|
|
ip6_sprintf(&ifra.ifra_addr.sin6_addr), if_name(ifp),
|
|
|
|
error));
|
2002-09-11 06:46:42 +04:00
|
|
|
return (NULL); /* ifaddr must not have been allocated. */
|
2002-06-09 01:22:29 +04:00
|
|
|
}
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-06-09 01:22:29 +04:00
|
|
|
ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (ia); /* this is always non-NULL */
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
in6_init_prefix_ltimes(struct nd_prefix *ndpr)
|
|
|
|
{
|
1999-12-13 18:17:17 +03:00
|
|
|
|
2001-10-17 14:55:09 +04:00
|
|
|
/* check if preferred lifetime > valid lifetime. RFC2462 5.5.3 (c) */
|
1999-06-28 10:36:47 +04:00
|
|
|
if (ndpr->ndpr_pltime > ndpr->ndpr_vltime) {
|
2001-04-04 10:28:41 +04:00
|
|
|
nd6log((LOG_INFO, "in6_init_prefix_ltimes: preferred lifetime"
|
1999-06-28 10:36:47 +04:00
|
|
|
"(%d) is greater than valid lifetime(%d)\n",
|
2001-04-04 10:28:41 +04:00
|
|
|
(u_int)ndpr->ndpr_pltime, (u_int)ndpr->ndpr_vltime));
|
1999-06-28 10:36:47 +04:00
|
|
|
return (EINVAL);
|
|
|
|
}
|
1999-12-13 18:17:17 +03:00
|
|
|
if (ndpr->ndpr_pltime == ND6_INFINITE_LIFETIME)
|
1999-06-28 10:36:47 +04:00
|
|
|
ndpr->ndpr_preferred = 0;
|
|
|
|
else
|
2003-06-24 11:39:24 +04:00
|
|
|
ndpr->ndpr_preferred = time.tv_sec + ndpr->ndpr_pltime;
|
1999-12-13 18:17:17 +03:00
|
|
|
if (ndpr->ndpr_vltime == ND6_INFINITE_LIFETIME)
|
1999-06-28 10:36:47 +04:00
|
|
|
ndpr->ndpr_expire = 0;
|
|
|
|
else
|
2003-06-24 11:39:24 +04:00
|
|
|
ndpr->ndpr_expire = time.tv_sec + ndpr->ndpr_vltime;
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-06-09 01:22:29 +04:00
|
|
|
in6_init_address_ltimes(struct nd_prefix *new, struct in6_addrlifetime *lt6)
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
1999-12-13 18:17:17 +03:00
|
|
|
|
|
|
|
/* Valid lifetime must not be updated unless explicitly specified. */
|
2002-06-09 01:22:29 +04:00
|
|
|
/* init ia6t_expire */
|
|
|
|
if (lt6->ia6t_vltime == ND6_INFINITE_LIFETIME)
|
|
|
|
lt6->ia6t_expire = 0;
|
|
|
|
else {
|
2003-06-24 11:39:24 +04:00
|
|
|
lt6->ia6t_expire = time.tv_sec;
|
2002-06-09 01:22:29 +04:00
|
|
|
lt6->ia6t_expire += lt6->ia6t_vltime;
|
1999-06-28 10:36:47 +04:00
|
|
|
}
|
1999-12-13 18:17:17 +03:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/* init ia6t_preferred */
|
1999-12-13 18:17:17 +03:00
|
|
|
if (lt6->ia6t_pltime == ND6_INFINITE_LIFETIME)
|
1999-06-28 10:36:47 +04:00
|
|
|
lt6->ia6t_preferred = 0;
|
|
|
|
else {
|
2003-06-24 11:39:24 +04:00
|
|
|
lt6->ia6t_preferred = time.tv_sec;
|
1999-06-28 10:36:47 +04:00
|
|
|
lt6->ia6t_preferred += lt6->ia6t_pltime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete all the routing table entries that use the specified gateway.
|
|
|
|
* XXX: this function causes search through all entries of routing table, so
|
2000-06-13 06:54:11 +04:00
|
|
|
* it shouldn't be called when acting as a router.
|
1999-06-28 10:36:47 +04:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
rt6_flush(gateway, ifp)
|
2001-10-17 14:55:09 +04:00
|
|
|
struct in6_addr *gateway;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
struct ifnet *ifp; /* unused */
|
1999-06-28 10:36:47 +04:00
|
|
|
{
|
|
|
|
struct radix_node_head *rnh = rt_tables[AF_INET6];
|
1999-07-04 06:01:15 +04:00
|
|
|
int s = splsoftnet();
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
/* We'll care only link-local addresses */
|
|
|
|
if (!IN6_IS_ADDR_LINKLOCAL(gateway)) {
|
|
|
|
splx(s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
rt6_deleteroute(rn, arg)
|
|
|
|
struct radix_node *rn;
|
|
|
|
void *arg;
|
|
|
|
{
|
|
|
|
#define SIN6(s) ((struct sockaddr_in6 *)s)
|
|
|
|
struct rtentry *rt = (struct rtentry *)rn;
|
|
|
|
struct in6_addr *gate = (struct in6_addr *)arg;
|
|
|
|
|
|
|
|
if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
|
|
|
if (!IN6_ARE_ADDR_EQUAL(gate, &SIN6(rt->rt_gateway)->sin6_addr))
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2001-10-17 14:55:09 +04:00
|
|
|
/*
|
|
|
|
* Do not delete a static route.
|
|
|
|
* XXX: this seems to be a bit ad-hoc. Should we consider the
|
|
|
|
* 'cloned' bit instead?
|
|
|
|
*/
|
|
|
|
if ((rt->rt_flags & RTF_STATIC) != 0)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
2001-10-17 14:55:09 +04:00
|
|
|
|
1999-06-28 10:36:47 +04:00
|
|
|
/*
|
|
|
|
* We delete only host route. This means, in particular, we don't
|
|
|
|
* delete default route.
|
|
|
|
*/
|
|
|
|
if ((rt->rt_flags & RTF_HOST) == 0)
|
2002-09-11 06:46:42 +04:00
|
|
|
return (0);
|
1999-06-28 10:36:47 +04:00
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
|
2002-06-09 01:22:29 +04:00
|
|
|
rt_mask(rt), rt->rt_flags, 0));
|
1999-06-28 10:36:47 +04:00
|
|
|
#undef SIN6
|
|
|
|
}
|
1999-12-13 18:17:17 +03:00
|
|
|
|
|
|
|
int
|
|
|
|
nd6_setdefaultiface(ifindex)
|
|
|
|
int ifindex;
|
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
2004-10-26 10:08:00 +04:00
|
|
|
if (ifindex < 0 || if_indexlim <= ifindex)
|
|
|
|
return (EINVAL);
|
|
|
|
if (ifindex != 0 && !ifindex2ifnet[ifindex])
|
2002-09-11 06:46:42 +04:00
|
|
|
return (EINVAL);
|
1999-12-13 18:17:17 +03:00
|
|
|
|
|
|
|
if (nd6_defifindex != ifindex) {
|
|
|
|
nd6_defifindex = ifindex;
|
2001-10-17 14:55:09 +04:00
|
|
|
if (nd6_defifindex > 0) {
|
1999-12-13 18:17:17 +03:00
|
|
|
nd6_defifp = ifindex2ifnet[nd6_defifindex];
|
2001-10-17 14:55:09 +04:00
|
|
|
} else
|
1999-12-13 18:17:17 +03:00
|
|
|
nd6_defifp = NULL;
|
Better support of IPv6 scoped addresses.
- most of the kernel code will not care about the actual encoding of
scope zone IDs and won't touch "s6_addr16[1]" directly.
- similarly, most of the kernel code will not care about link-local
scoped addresses as a special case.
- scope boundary check will be stricter. For example, the current
*BSD code allows a packet with src=::1 and dst=(some global IPv6
address) to be sent outside of the node, if the application do:
s = socket(AF_INET6);
bind(s, "::1");
sendto(s, some_global_IPv6_addr);
This is clearly wrong, since ::1 is only meaningful within a single
node, but the current implementation of the *BSD kernel cannot
reject this attempt.
- and, while there, don't try to remove the ff02::/32 interface route
entry in in6_ifdetach() as it's already gone.
This also includes some level of support for the standard source
address selection algorithm defined in RFC3484, which will be
completed on in the future.
From the KAME project via JINMEI Tatuya.
Approved by core@.
2006-01-21 03:15:35 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Our current implementation assumes one-to-one maping between
|
|
|
|
* interfaces and links, so it would be natural to use the
|
|
|
|
* default interface as the default link.
|
|
|
|
*/
|
|
|
|
scope6_setdefault(nd6_defifp);
|
1999-12-13 18:17:17 +03:00
|
|
|
}
|
|
|
|
|
2002-09-11 06:46:42 +04:00
|
|
|
return (error);
|
1999-12-13 18:17:17 +03:00
|
|
|
}
|