svn commit: r197138 - in head: sbin/ifconfig share/man/man4 sys/netinet6 usr.sbin/ndp

Hiroki Sato hrs at FreeBSD.org
Sat Sep 12 22:08:20 UTC 2009


Author: hrs
Date: Sat Sep 12 22:08:20 2009
New Revision: 197138
URL: http://svn.freebsd.org/changeset/base/197138

Log:
  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

Added:
  head/sbin/ifconfig/af_nd6.c   (contents, props changed)
Modified:
  head/sbin/ifconfig/Makefile
  head/sbin/ifconfig/af_inet6.c
  head/sbin/ifconfig/ifconfig.8
  head/share/man/man4/inet6.4
  head/sys/netinet6/in6.c
  head/sys/netinet6/in6_ifattach.c
  head/sys/netinet6/in6_proto.c
  head/sys/netinet6/ip6_input.c
  head/sys/netinet6/nd6.c
  head/sys/netinet6/nd6.h
  head/sys/netinet6/nd6_nbr.c
  head/sys/netinet6/nd6_rtr.c
  head/usr.sbin/ndp/ndp.8
  head/usr.sbin/ndp/ndp.c

Modified: head/sbin/ifconfig/Makefile
==============================================================================
--- head/sbin/ifconfig/Makefile	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/sbin/ifconfig/Makefile	Sat Sep 12 22:08:20 2009	(r197138)
@@ -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

Modified: head/sbin/ifconfig/af_inet6.c
==============================================================================
--- head/sbin/ifconfig/af_inet6.c	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/sbin/ifconfig/af_inet6.c	Sat Sep 12 22:08:20 2009	(r197138)
@@ -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),

Added: head/sbin/ifconfig/af_nd6.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sbin/ifconfig/af_nd6.c	Sat Sep 12 22:08:20 2009	(r197138)
@@ -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);
+}

Modified: head/sbin/ifconfig/ifconfig.8
==============================================================================
--- head/sbin/ifconfig/ifconfig.8	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/sbin/ifconfig/ifconfig.8	Sat Sep 12 22:08:20 2009	(r197138)
@@ -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 previous
 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.
-.Pp
-If you delete such an address using
-.Nm ,
-the kernel may act very odd.
-Do this at your own risk.
+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
+Do not configure IPv6 addresses with no link-local address by using
+.Nm .
+It can result in unexpected behaviors of the kernel.

Modified: head/share/man/man4/inet6.4
==============================================================================
--- head/share/man/man4/inet6.4	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/share/man/man4/inet6.4	Sat Sep 12 22:08:20 2009	(r197138)
@@ -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 fragm
 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

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/sys/netinet6/in6.c	Sat Sep 12 22:08:20 2009	(r197138)
@@ -917,6 +917,10 @@ in6_update_ifa(struct ifnet *ifp, struct
 	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
 			 * 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:

Modified: head/sys/netinet6/in6_ifattach.c
==============================================================================
--- head/sys/netinet6/in6_ifattach.c	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/sys/netinet6/in6_ifattach.c	Sat Sep 12 22:08:20 2009	(r197138)
@@ -750,14 +750,18 @@ in6_ifattach(struct ifnet *ifp, struct i
 	/*
 	 * 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);
 	}

Modified: head/sys/netinet6/in6_proto.c
==============================================================================
--- head/sys/netinet6/in6_proto.c	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/sys/netinet6/in6_proto.c	Sat Sep 12 22:08:20 2009	(r197138)
@@ -497,7 +497,9 @@ SYSCTL_VNET_STRUCT(_net_inet6_ip6, IPV6C
 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
 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,

Modified: head/sys/netinet6/ip6_input.c
==============================================================================
--- head/sys/netinet6/ip6_input.c	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/sys/netinet6/ip6_input.c	Sat Sep 12 22:08:20 2009	(r197138)
@@ -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 */

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/sys/netinet6/nd6.c	Sat Sep 12 22:08:20 2009	(r197138)
@@ -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, stru
 			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, stru
 	 * 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
 		 */

Modified: head/sys/netinet6/nd6.h
==============================================================================
--- head/sys/netinet6/nd6.h	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/sys/netinet6/nd6.h	Sat Sep 12 22:08:20 2009	(r197138)
@@ -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

Modified: head/sys/netinet6/nd6_nbr.c
==============================================================================
--- head/sys/netinet6/nd6_nbr.c	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/sys/netinet6/nd6_nbr.c	Sat Sep 12 22:08:20 2009	(r197138)
@@ -1198,6 +1198,8 @@ nd6_dad_start(struct ifaddr *ifa, int de
 	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;

Modified: head/sys/netinet6/nd6_rtr.c
==============================================================================
--- head/sys/netinet6/nd6_rtr.c	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/sys/netinet6/nd6_rtr.c	Sat Sep 12 22:08:20 2009	(r197138)
@@ -126,7 +126,7 @@ nd6_rs_input(struct mbuf *m, int off, in
 	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, in
 
 	/*
 	 * 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;
 	}

Modified: head/usr.sbin/ndp/ndp.8
==============================================================================
--- head/usr.sbin/ndp/ndp.8	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/usr.sbin/ndp/ndp.8	Sat Sep 12 22:08:20 2009	(r197138)
@@ -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 ENETDOW
 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)

Modified: head/usr.sbin/ndp/ndp.c
==============================================================================
--- head/usr.sbin/ndp/ndp.c	Sat Sep 12 21:44:34 2009	(r197137)
+++ head/usr.sbin/ndp/ndp.c	Sat Sep 12 22:08:20 2009	(r197138)
@@ -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 ");


More information about the svn-src-all mailing list