Improve flexibility of receiving Router Advertisement and

automatic link-local address configuration:

- Convert a sysctl net.inet6.ip6.accept_rtadv to one for the
  default value of a per-IF flag ND6_IFF_ACCEPT_RTADV, not a
  global knob.  The default value of the sysctl is 0.

- Add a new per-IF flag ND6_IFF_AUTO_LINKLOCAL and convert a
  sysctl net.inet6.ip6.auto_linklocal to one for its default
  value.  The default value of the sysctl is 1.

- Make ND6_IFF_IFDISABLED more robust.  It can be used to disable
  IPv6 functionality of an interface now.

- Receiving RA is allowed if ip6_forwarding==0 *and*
  ND6_IFF_ACCEPT_RTADV is set on that interface.  The former
  condition will be revisited later to support a "host + router" box
  like IPv6 CPE router.  The current behavior is compatible with
  the older releases of FreeBSD.

- The ifconfig(8) now supports these ND6 flags as well as "nud",
  "prefer_source", and "disabled" in ndp(8).  The ndp(8) now
  supports "auto_linklocal".

Discussed with:	bz and jinmei
Reviewed by:	bz
MFC after:	3 days
This commit is contained in:
Hiroki Sato 2009-09-12 22:08:20 +00:00
parent 446e861708
commit a283298ce3
15 changed files with 469 additions and 54 deletions

View File

@ -18,6 +18,7 @@ SRCS+= af_link.c # LLC support
SRCS+= af_inet.c # IPv4 support
SRCS+= af_inet6.c # IPv6 support
SRCS+= af_atalk.c # AppleTalk support
SRCS+= af_nd6.c # ND6 support
SRCS+= ifclone.c # clone device support
SRCS+= ifmac.c # MAC support

View File

@ -67,6 +67,9 @@ static int prefix(void *, int);
static char *sec2str(time_t);
static int explicit_prefix = 0;
extern void setnd6flags(const char *, int, int, const struct afswtch *);
extern void setnd6defif(const char *, int, int, const struct afswtch *);
static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/
static void
@ -493,6 +496,18 @@ static struct cmd inet6_cmds[] = {
DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED, setip6flags),
DEF_CMD("autoconf", IN6_IFF_AUTOCONF, setip6flags),
DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags),
DEF_CMD("accept_rtadv", ND6_IFF_ACCEPT_RTADV, setnd6flags),
DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV, setnd6flags),
DEF_CMD("defaultif", 1, setnd6defif),
DEF_CMD("-defaultif", -1, setnd6defif),
DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags),
DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags),
DEF_CMD("nud", ND6_IFF_PERFORMNUD, setnd6flags),
DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags),
DEF_CMD("prefer_source",ND6_IFF_PREFER_SOURCE, setnd6flags),
DEF_CMD("-prefer_source",-ND6_IFF_PREFER_SOURCE,setnd6flags),
DEF_CMD("auto_linklocal",ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
DEF_CMD("-auto_linklocal",-ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
DEF_CMD_ARG("pltime", setip6pltime),
DEF_CMD_ARG("vltime", setip6vltime),
DEF_CMD("eui64", 0, setip6eui64),

251
sbin/ifconfig/af_nd6.c Normal file
View File

@ -0,0 +1,251 @@
/*
* Copyright (c) 2009 Hiroki Sato. All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/route.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/if_var.h>
#include <netinet/in_var.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet6/nd6.h>
#include "ifconfig.h"
#define MAX_SYSCTL_TRY 5
static struct nd6_opt_list {
const char *label;
u_int mask;
} nd6_opts[] = {
{ "IFDISABLED", ND6_IFF_IFDISABLED, },
{ "PERFORMNUD", ND6_IFF_PERFORMNUD, },
{ "ACCEPT_RTADV", ND6_IFF_ACCEPT_RTADV, },
{ "PREFER_SOURCE", ND6_IFF_PREFER_SOURCE, },
{ "AUTO_LINKLOCAL", ND6_IFF_AUTO_LINKLOCAL, },
};
static int isnd6defif(int);
void setnd6flags(const char *, int, int, const struct afswtch *);
void setnd6defif(const char *, int, int, const struct afswtch *);
void
setnd6flags(const char *dummyaddr __unused,
int d, int s,
const struct afswtch *afp)
{
struct in6_ndireq nd;
int error;
memset(&nd, 0, sizeof(nd));
strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
error = ioctl(s, SIOCGIFINFO_IN6, &nd);
if (error) {
warn("ioctl(SIOCGIFINFO_IN6)");
return;
}
if (d < 0)
nd.ndi.flags &= ~(-d);
else
nd.ndi.flags |= d;
error = ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd);
if (error)
warn("ioctl(SIOCSIFINFO_IN6)");
}
void
setnd6defif(const char *dummyaddr __unused,
int d, int s,
const struct afswtch *afp)
{
struct in6_ndifreq ndifreq;
int ifindex;
int error;
memset(&ndifreq, 0, sizeof(ndifreq));
strncpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname));
if (d < 0) {
if (isnd6defif(s)) {
/* ifindex = 0 means to remove default if */
ifindex = 0;
} else
return;
} else if ((ifindex = if_nametoindex(ndifreq.ifname)) == 0) {
warn("if_nametoindex(%s)", ndifreq.ifname);
return;
}
ndifreq.ifindex = ifindex;
error = ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq);
if (error)
warn("ioctl(SIOCSDEFIFACE_IN6)");
}
static int
isnd6defif(int s)
{
struct in6_ndifreq ndifreq;
unsigned int ifindex;
int error;
memset(&ndifreq, 0, sizeof(ndifreq));
strncpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname));
ifindex = if_nametoindex(ndifreq.ifname);
error = ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq);
if (error) {
warn("ioctl(SIOCGDEFIFACE_IN6)");
return (error);
}
return (ndifreq.ifindex == ifindex);
}
static void
nd6_status(int s)
{
struct in6_ndireq nd;
struct rt_msghdr *rtm;
size_t needed;
char *buf, *next;
int mib[6], ntry;
int s6;
int i, error;
int isinet6, isdefif;
int nopts;
/* Check if the interface has at least one IPv6 address. */
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET6;
mib[4] = NET_RT_IFLIST;
mib[5] = if_nametoindex(ifr.ifr_name);
/* Try to prevent a race between two sysctls. */
ntry = 0;
do {
error = sysctl(mib, 6, NULL, &needed, NULL, 0);
if (error) {
warn("sysctl(NET_RT_IFLIST)/estimate");
return;
}
buf = malloc(needed);
if (buf == NULL) {
warn("malloc for sysctl(NET_RT_IFLIST) failed");
return;
}
if ((error = sysctl(mib, 6, buf, &needed, NULL, 0)) < 0) {
if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
warn("sysctl(NET_RT_IFLIST)/get");
free(buf);
return;
}
free(buf);
buf = NULL;
}
} while (buf == NULL);
isinet6 = 0;
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
if (rtm->rtm_version != RTM_VERSION)
continue;
if (rtm->rtm_type == RTM_NEWADDR) {
isinet6 = 1;
break;
}
}
free(buf);
if (!isinet6)
return;
memset(&nd, 0, sizeof(nd));
strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
warn("socket(AF_INET6, SOCK_DGRAM)");
return;
}
error = ioctl(s6, SIOCGIFINFO_IN6, &nd);
if (error) {
warn("ioctl(SIOCGIFINFO_IN6)");
close(s6);
return;
}
isdefif = isnd6defif(s6);
close(s6);
if (nd.ndi.flags == 0 && !isdefif)
return;
nopts = 0;
printf("\tnd6 options=%d<", nd.ndi.flags);
for (i=0; i < sizeof(nd6_opts)/sizeof(nd6_opts[0]); i++) {
if (nd.ndi.flags & nd6_opts[i].mask) {
if (nopts++)
printf(",");
printf("%s", nd6_opts[i].label);
}
}
if (isdefif) {
if (nopts)
printf(",");
printf("DEFAULTIF");
}
printf(">\n");
}
static struct afswtch af_nd6 = {
.af_name = "nd6",
.af_af = AF_LOCAL,
.af_other_status= nd6_status,
};
static __constructor void
nd6_ctor(void)
{
af_register(&af_nd6);
}

View File

@ -28,7 +28,7 @@
.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
.\" $FreeBSD$
.\"
.Dd July 8, 2009
.Dd September 2, 2009
.Dt IFCONFIG 8
.Os
.Sh NAME
@ -598,6 +598,48 @@ If the interface was reset when previously marked down,
the hardware will be re-initialized.
.El
.Pp
The following parameters are for ICMPv6 Neightbor Discovery Protocol:
.Bl -tag -width indent
.It Cm accept_rtadv
Set a flag to enable accepting ICMPv6 Router Advertisement messages.
.It Cm -accept_rtadv
Clear a flag
.Cm accept_rtadv .
.It Cm auto_linklocal
Set a flag to perform automatic link-local address configuration when
the interface becomes avalilable.
.It Cm -auto_linklocal
Clear a flag
.Cm auto_linklocal .
.It Cm defaultif
Set the specified interface as the default route when there is no
default router.
.It Cm -defaultif
Clear a flag
.Cm defaultif .
.It Cm ifdisabled
Set a flag to disable all of IPv6 network communications on the
specified interface.
.It Cm -ifdisabled
Clear a flag
.Cm ifdisabled .
When this flag is cleared and
.Cm auto_linklocal
flag is enabled, automatic configuration of a link-local address is
performed.
.It Cm nud
Set a flag to enable Neighbor Unreachability Detection.
.It Cm -nud
Clear a flag
.Cm nud .
.It Cm prefer_source
Set a flag to prefer addesses on the interface as candidates of the
source address for outgoing packets.
.It Cm -prefer_source
Clear a flag
.Cm prefer_source .
.El
.Pp
The following parameters are specific to cloning
IEEE 802.11 wireless interfaces with the
.Cm create
@ -2421,6 +2463,9 @@ from the interface
.Li ed0 :
.Dl # ifconfig ed0 inet 192.0.2.45 -alias
.Pp
Enable IPv6 functionality of the interface:
.Dl # ifconfig em0 inet6 -ifdisabled
.Pp
Add the IPv6 address
.Li 2001:DB8:DBDB::123/48
to the interface
@ -2475,12 +2520,13 @@ utility appeared in
Basic IPv6 node operation requires a link-local address on each
interface configured for IPv6.
Normally, such an address is automatically configured by the
kernel on each interface added to the system; this behaviour may
be disabled by setting the sysctl MIB variable
.Va net.inet6.ip6.auto_linklocal
to 0.
kernel on each interface added to the system or enabled; this behavior may
be disabled by setting per-interface flag
.Cm -auto_linklocal .
The default value of this flag is 1 and can be disabled by using the sysctl
MIB variable
.Va net.inet6.ip6.auto_linklocal .
.Pp
If you delete such an address using
.Nm ,
the kernel may act very odd.
Do this at your own risk.
Do not configure IPv6 addresses with no link-local address by using
.Nm .
It can result in unexpected behaviors of the kernel.

View File

@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd January 29, 1999
.Dd September 2, 2009
.Dt INET6 4
.Os
.Sh NAME
@ -307,7 +307,8 @@ Integer: default maximum number of fragmented packets the node will accept.
The flag is provided basically for avoiding possible DoS attacks.
.It Dv IPV6CTL_ACCEPT_RTADV
.Pq ip6.accept_rtadv
Boolean: enable/disable receiving of
Boolean: the default value of a per-interface flag to
enable/disable receiving of
.Tn ICMPv6
router advertisement packets,
and autoconfiguration of address prefixes and default routers.
@ -315,6 +316,11 @@ The node must be a host
(not a router)
for the option to be meaningful.
Defaults to off.
.It Dv IPV6CTL_AUTO_LINKLOCAL
.Pq ip6.auto_linklocal
Boolean: the default value of a per-interface flag to
enable/disable performing automatic link-local address configuration.
Defaults to on.
.It Dv IPV6CTL_KEEPFAITH
.Pq ip6.keepfaith
Boolean: enable/disable

View File

@ -917,6 +917,10 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
if (hostIsNew && in6if_do_dad(ifp))
ia->ia6_flags |= IN6_IFF_TENTATIVE;
/* DAD should be performed after ND6_IFF_IFDISABLED is cleared. */
if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
ia->ia6_flags |= IN6_IFF_TENTATIVE;
/*
* We are done if we have simply modified an existing address.
*/
@ -954,7 +958,7 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
* being configured. It also means delaying
* transmission of the corresponding MLD report to
* avoid report collision.
* [draft-ietf-ipv6-rfc2462bis-02.txt]
* [RFC 4861, Section 6.3.7]
*/
delay = arc4random() %
(MAX_RTR_SOLICITATION_DELAY * hz);
@ -2197,6 +2201,9 @@ in6if_do_dad(struct ifnet *ifp)
if ((ifp->if_flags & IFF_LOOPBACK) != 0)
return (0);
if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED)
return (0);
switch (ifp->if_type) {
#ifdef IFT_DUMMY
case IFT_DUMMY:

View File

@ -750,14 +750,18 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
/*
* assign a link-local address, if there's none.
*/
if (V_ip6_auto_linklocal && ifp->if_type != IFT_BRIDGE) {
if (ifp->if_type != IFT_BRIDGE &&
!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) {
int error;
ia = in6ifa_ifpforlinklocal(ifp, 0);
if (ia == NULL) {
if (in6_ifattach_linklocal(ifp, altifp) == 0) {
/* linklocal address assigned */
} else {
/* failed to assign linklocal address. bark? */
}
error = in6_ifattach_linklocal(ifp, altifp);
if (error)
log(LOG_NOTICE, "in6_ifattach_linklocal: "
"failed to add a link-local addr to %s\n",
if_name(ifp));
} else
ifa_free(&ia->ia_ifa);
}

View File

@ -497,7 +497,9 @@ SYSCTL_VNET_STRUCT(_net_inet6_ip6, IPV6CTL_STATS, stats, CTLFLAG_RD,
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGPACKETS, maxfragpackets,
CTLFLAG_RW, &VNET_NAME(ip6_maxfragpackets), 0, "");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_ACCEPT_RTADV, accept_rtadv,
CTLFLAG_RW, &VNET_NAME(ip6_accept_rtadv), 0, "");
CTLFLAG_RW, &VNET_NAME(ip6_accept_rtadv), 0,
"Default value of per-interface flag for accepting ICMPv6 Router"
"Advertisement messages");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_KEEPFAITH, keepfaith, CTLFLAG_RW,
&VNET_NAME(ip6_keepfaith), 0, "");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_LOG_INTERVAL, log_interval,
@ -527,7 +529,9 @@ SYSCTL_VNET_PROC(_net_inet6_ip6, IPV6CTL_TEMPVLTIME, tempvltime,
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_V6ONLY, v6only, CTLFLAG_RW,
&VNET_NAME(ip6_v6only), 0, "");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_AUTO_LINKLOCAL, auto_linklocal,
CTLFLAG_RW, &VNET_NAME(ip6_auto_linklocal), 0, "");
CTLFLAG_RW, &VNET_NAME(ip6_auto_linklocal), 0,
"Default value of per-interface flag for automatically adding an IPv6"
" link-local address to interfaces when attached");
SYSCTL_VNET_STRUCT(_net_inet6_ip6, IPV6CTL_RIP6STATS, rip6stats, CTLFLAG_RD,
&VNET_NAME(rip6stat), rip6stat, "");
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_PREFER_TEMPADDR, prefer_tempaddr,

View File

@ -175,7 +175,7 @@ ip6_init(void)
#ifdef IP6_AUTO_LINKLOCAL
V_ip6_auto_linklocal = IP6_AUTO_LINKLOCAL;
#else
V_ip6_auto_linklocal = 1; /* enable by default */
V_ip6_auto_linklocal = 1; /* enabled by default */
#endif
TUNABLE_INT_FETCH("net.inet6.ip6.auto_linklocal",
&V_ip6_auto_linklocal);
@ -196,7 +196,7 @@ ip6_init(void)
V_ip6_sendredirects = IPV6_SENDREDIRECTS;
V_ip6_defhlim = IPV6_DEFHLIM;
V_ip6_defmcasthlim = IPV6_DEFAULT_MULTICAST_HOPS;
V_ip6_accept_rtadv = 0; /* "IPV6FORWARDING ? 0 : 1" is dangerous */
V_ip6_accept_rtadv = 0;
V_ip6_log_interval = 5;
V_ip6_hdrnestlimit = 15; /* How many header options will we process? */
V_ip6_dad_count = 1; /* DupAddrDetectionTransmits */

View File

@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip6_var.h>
#include <netinet6/scope6_var.h>
#include <netinet6/nd6.h>
#include <netinet6/in6_ifattach.h>
#include <netinet/icmp6.h>
#include <sys/limits.h>
@ -212,12 +213,16 @@ nd6_ifattach(struct ifnet *ifp)
nd->basereachable = REACHABLE_TIME;
nd->reachable = ND_COMPUTE_RTIME(nd->basereachable);
nd->retrans = RETRANS_TIMER;
/*
* Note that the default value of ip6_accept_rtadv is 0, which means
* we won't accept RAs by default even if we set ND6_IFF_ACCEPT_RTADV
* here.
*/
nd->flags = (ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV);
nd->flags = ND6_IFF_PERFORMNUD;
/* A loopback interface always has ND6_IFF_AUTO_LINKLOCAL. */
if (V_ip6_auto_linklocal || (ifp->if_flags & IFF_LOOPBACK))
nd->flags |= ND6_IFF_AUTO_LINKLOCAL;
/* A loopback interface does not need to accept RTADV. */
if (V_ip6_accept_rtadv && !(ifp->if_flags & IFF_LOOPBACK))
nd->flags |= ND6_IFF_ACCEPT_RTADV;
/* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */
nd6_setmtu0(ifp, nd);
@ -843,13 +848,9 @@ nd6_purge(struct ifnet *ifp)
if (V_nd6_defifindex == ifp->if_index)
nd6_setdefaultiface(0);
if (!V_ip6_forwarding && V_ip6_accept_rtadv) { /* XXX: too restrictive? */
/* refresh default router list
*
*
*/
if (!V_ip6_forwarding && ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
/* Refresh default router list. */
defrouter_select();
}
/* XXXXX
@ -1296,6 +1297,69 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
ND_IFINFO(ifp)->chlim = ND.chlim;
/* FALLTHROUGH */
case SIOCSIFINFO_FLAGS:
{
struct ifaddr *ifa;
struct in6_ifaddr *ia;
if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
!(ND.flags & ND6_IFF_IFDISABLED)) {
/* ifdisabled 1->0 transision */
/*
* If the interface is marked as ND6_IFF_IFDISABLED and
* has an link-local address with IN6_IFF_DUPLICATED,
* do not clear ND6_IFF_IFDISABLED.
* See RFC 4862, Section 5.4.5.
*/
int duplicated_linklocal = 0;
IF_ADDR_LOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ia = (struct in6_ifaddr *)ifa;
if ((ia->ia6_flags & IN6_IFF_DUPLICATED) &&
IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) {
duplicated_linklocal = 1;
break;
}
}
IF_ADDR_UNLOCK(ifp);
if (duplicated_linklocal) {
ND.flags |= ND6_IFF_IFDISABLED;
log(LOG_ERR, "Cannot enable an interface"
" with a link-local address marked"
" duplicate.\n");
} else {
ND_IFINFO(ifp)->flags &= ~ND6_IFF_IFDISABLED;
in6_if_up(ifp);
}
} else if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
(ND.flags & ND6_IFF_IFDISABLED)) {
/* ifdisabled 0->1 transision */
/* Mark all IPv6 address as tentative. */
ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
IF_ADDR_LOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ia = (struct in6_ifaddr *)ifa;
ia->ia6_flags |= IN6_IFF_TENTATIVE;
}
IF_ADDR_UNLOCK(ifp);
}
if (!(ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) &&
(ND.flags & ND6_IFF_AUTO_LINKLOCAL)) {
/* auto_linklocal 0->1 transision */
/* If no link-local address on ifp, configure */
ND_IFINFO(ifp)->flags |= ND6_IFF_AUTO_LINKLOCAL;
in6_ifattach(ifp, NULL);
}
}
ND_IFINFO(ifp)->flags = ND.flags;
break;
#undef ND
@ -1633,7 +1697,8 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
* for those are not autoconfigured hosts, we explicitly avoid such
* cases for safety.
*/
if (do_update && router && !V_ip6_forwarding && V_ip6_accept_rtadv) {
if (do_update && router && !V_ip6_forwarding &&
ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
/*
* guaranteed recursion
*/

View File

@ -84,6 +84,7 @@ struct nd_ifinfo {
* DAD failure. (XXX: not ND-specific)
*/
#define ND6_IFF_DONT_SET_IFROUTE 0x10
#define ND6_IFF_AUTO_LINKLOCAL 0x20
#define ND6_CREATE LLE_CREATE
#define ND6_EXCLUSIVE LLE_EXCLUSIVE

View File

@ -1198,6 +1198,8 @@ nd6_dad_start(struct ifaddr *ifa, int delay)
if (!(ifa->ifa_ifp->if_flags & IFF_UP)) {
return;
}
if (ND_IFINFO(ifa->ifa_ifp)->flags & ND6_IFF_IFDISABLED)
return;
if (nd6_dad_find(ifa) != NULL) {
/* DAD already in progress */
return;
@ -1402,7 +1404,7 @@ nd6_dad_duplicated(struct ifaddr *ifa)
* identifier based on the hardware address which is supposed to be
* uniquely assigned (e.g., EUI-64 for an Ethernet interface), IP
* operation on the interface SHOULD be disabled.
* [rfc2462bis-03 Section 5.4.5]
* [RFC 4862, Section 5.4.5]
*/
if (IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) {
struct in6_addr in6;

View File

@ -126,7 +126,7 @@ nd6_rs_input(struct mbuf *m, int off, int icmp6len)
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
/* If I'm not a router, ignore it. */
if (V_ip6_accept_rtadv != 0 || V_ip6_forwarding != 1)
if (!V_ip6_forwarding)
goto freeit;
/* Sanity checks */
@ -212,12 +212,10 @@ nd6_ra_input(struct mbuf *m, int off, int icmp6len)
/*
* We only accept RAs only when
* the system-wide variable allows the acceptance, and
* the node is not a router and
* per-interface variable allows RAs on the receiving interface.
*/
if (V_ip6_accept_rtadv == 0)
goto freeit;
if (!(ndi->flags & ND6_IFF_ACCEPT_RTADV))
if (V_ip6_forwarding || !(ndi->flags & ND6_IFF_ACCEPT_RTADV))
goto freeit;
if (ip6->ip6_hlim != 255) {
@ -557,7 +555,7 @@ defrtrlist_del(struct nd_defrouter *dr)
* Flush all the routing table entries that use the router
* as a next hop.
*/
if (!V_ip6_forwarding && V_ip6_accept_rtadv) /* XXX: better condition? */
if (!V_ip6_forwarding)
rt6_flush(&dr->rtaddr, dr->ifp);
if (dr->installed) {
@ -621,10 +619,10 @@ defrouter_select(void)
* if the node is not an autoconfigured host, we explicitly exclude
* such cases here for safety.
*/
if (V_ip6_forwarding || !V_ip6_accept_rtadv) {
if (V_ip6_forwarding) {
nd6log((LOG_WARNING,
"defrouter_select: called unexpectedly (forwarding=%d, "
"accept_rtadv=%d)\n", V_ip6_forwarding, V_ip6_accept_rtadv));
"defrouter_select: called unexpectedly (forwarding=%d)\n",
V_ip6_forwarding));
splx(s);
return;
}

View File

@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 17, 1998
.Dd September 2, 2009
.Dt NDP 8
.Os
.\"
@ -182,11 +182,16 @@ NUD is usually turned on by default.
Specify whether or not to accept Router Advertisement messages
received on the
.Ar interface .
Note that the kernel does not accept Router Advertisement messages
unless the
.Li net.inet6.ip6.accept_rtadv
variable is non-0, even if the flag is on.
This flag is set to 1 by default.
This flag is set by
.Va net.inet6.ip6.accept_rtadv
sysctl variable.
.It Ic auto_linklocal
Specify whether or not to perform automatic link-local address configuration
on
.Ar interface .
This flag is set by
.Va net.inet6.ip6.auto_linklocal
sysctl variable.
.It Ic prefer_source
Prefer addresses on the
.Ar interface
@ -204,9 +209,8 @@ In the sending case, an error of ENETDOWN will be returned to the
application.
This flag is typically set automatically in the kernel as a result of
a certain failure of Duplicate Address Detection.
While the flag can be set or cleared by hand with the
.Nm
command, it is not generally advisable to modify this flag manually.
If the auto_linklocal per-interface flag is set, automatic link-local
address configuration is performed again when this flag is cleared.
.It Ic basereachable Ns Li = Ns Pq Ar number
Specify the BaseReachbleTimer on the interface in millisecond.
.It Ic retrans Ns Li = Ns Pq Ar number
@ -253,6 +257,10 @@ Most useful when used with
The
.Nm
utility first appeared in the WIDE Hydrangea IPv6 protocol stack kit.
The
.Fl I Ar auto_linklocal
flag first appeared in
.Fx 8.0 .
.\"
.\" .Sh BUGS
.\" (to be written)

View File

@ -1004,6 +1004,9 @@ ifinfo(ifname, argc, argv)
#ifdef ND6_IFF_ACCEPT_RTADV
SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV);
#endif
#ifdef ND6_IFF_AUTO_LINKLOCAL
SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL);
#endif
#ifdef ND6_IFF_PREFER_SOURCE
SETFLAG("prefer_source", ND6_IFF_PREFER_SOURCE);
#endif
@ -1076,6 +1079,10 @@ ifinfo(ifname, argc, argv)
if ((ND.flags & ND6_IFF_ACCEPT_RTADV))
printf("accept_rtadv ");
#endif
#ifdef ND6_IFF_AUTO_LINKLOCAL
if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL))
printf("auto_linklocal ");
#endif
#ifdef ND6_IFF_PREFER_SOURCE
if ((ND.flags & ND6_IFF_PREFER_SOURCE))
printf("prefer_source ");