aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-06-28 01:18:38 -0400
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-07-03 04:51:56 -0400
commit1b34be74cbf18f5d58cc85c7c4afcd9f7d74accd (patch)
tree46cae932b628e96af0a269f8653684298d5ea65f
parent778d80be52699596bf70e0eb0761cf5e1e46088d (diff)
ipv6 addrconf: add accept_dad sysctl to control DAD operation.
- If 0, disable DAD. - If 1, perform DAD (default). - If >1, perform DAD and disable IPv6 operation if DAD for MAC-based link-local address has been failed (RFC4862 5.4.5). We do not follow RFC4862 by default. Refer to the netdev thread entitled "Linux IPv6 DAD not full conform to RFC 4862 ?" http://www.spinics.net/lists/netdev/msg52027.html Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
-rw-r--r--Documentation/networking/ip-sysctl.txt7
-rw-r--r--include/linux/ipv6.h2
-rw-r--r--net/ipv6/addrconf.c35
3 files changed, 44 insertions, 0 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index dae980e8f1b9..72f6d52e52e6 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1029,6 +1029,13 @@ disable_ipv6 - BOOLEAN
1029 Disable IPv6 operation. 1029 Disable IPv6 operation.
1030 Default: FALSE (enable IPv6 operation) 1030 Default: FALSE (enable IPv6 operation)
1031 1031
1032accept_dad - INTEGER
1033 Whether to accept DAD (Duplicate Address Detection).
1034 0: Disable DAD
1035 1: Enable DAD (default)
1036 2: Enable DAD, and disable IPv6 operation if MAC-based duplicate
1037 link-local address has been found.
1038
1032icmp/*: 1039icmp/*:
1033ratelimit - INTEGER 1040ratelimit - INTEGER
1034 Limit the maximal rates for sending ICMPv6 packets. 1041 Limit the maximal rates for sending ICMPv6 packets.
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index d9d7f9b69eb4..391ad0843a46 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -164,6 +164,7 @@ struct ipv6_devconf {
164 __s32 mc_forwarding; 164 __s32 mc_forwarding;
165#endif 165#endif
166 __s32 disable_ipv6; 166 __s32 disable_ipv6;
167 __s32 accept_dad;
167 void *sysctl; 168 void *sysctl;
168}; 169};
169 170
@@ -196,6 +197,7 @@ enum {
196 DEVCONF_ACCEPT_SOURCE_ROUTE, 197 DEVCONF_ACCEPT_SOURCE_ROUTE,
197 DEVCONF_MC_FORWARDING, 198 DEVCONF_MC_FORWARDING,
198 DEVCONF_DISABLE_IPV6, 199 DEVCONF_DISABLE_IPV6,
200 DEVCONF_ACCEPT_DAD,
199 DEVCONF_MAX 201 DEVCONF_MAX
200}; 202};
201 203
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 8c5cff50bbed..2ec73e62202c 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -119,6 +119,7 @@ static void ipv6_regen_rndid(unsigned long data);
119static int desync_factor = MAX_DESYNC_FACTOR * HZ; 119static int desync_factor = MAX_DESYNC_FACTOR * HZ;
120#endif 120#endif
121 121
122static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
122static int ipv6_count_addresses(struct inet6_dev *idev); 123static int ipv6_count_addresses(struct inet6_dev *idev);
123 124
124/* 125/*
@@ -184,6 +185,7 @@ struct ipv6_devconf ipv6_devconf __read_mostly = {
184 .proxy_ndp = 0, 185 .proxy_ndp = 0,
185 .accept_source_route = 0, /* we do not accept RH0 by default. */ 186 .accept_source_route = 0, /* we do not accept RH0 by default. */
186 .disable_ipv6 = 0, 187 .disable_ipv6 = 0,
188 .accept_dad = 1,
187}; 189};
188 190
189static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { 191static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -217,6 +219,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
217 .proxy_ndp = 0, 219 .proxy_ndp = 0,
218 .accept_source_route = 0, /* we do not accept RH0 by default. */ 220 .accept_source_route = 0, /* we do not accept RH0 by default. */
219 .disable_ipv6 = 0, 221 .disable_ipv6 = 0,
222 .accept_dad = 1,
220}; 223};
221 224
222/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ 225/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
@@ -380,6 +383,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
380 */ 383 */
381 in6_dev_hold(ndev); 384 in6_dev_hold(ndev);
382 385
386 if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
387 ndev->cnf.accept_dad = -1;
388
383#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) 389#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
384 if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) { 390 if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) {
385 printk(KERN_INFO 391 printk(KERN_INFO
@@ -1421,6 +1427,20 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
1421 1427
1422void addrconf_dad_failure(struct inet6_ifaddr *ifp) 1428void addrconf_dad_failure(struct inet6_ifaddr *ifp)
1423{ 1429{
1430 struct inet6_dev *idev = ifp->idev;
1431 if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) {
1432 struct in6_addr addr;
1433
1434 addr.s6_addr32[0] = htonl(0xfe800000);
1435 addr.s6_addr32[1] = 0;
1436
1437 if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) &&
1438 ipv6_addr_equal(&ifp->addr, &addr)) {
1439 /* DAD failed for link-local based on MAC address */
1440 idev->cnf.disable_ipv6 = 1;
1441 }
1442 }
1443
1424 if (net_ratelimit()) 1444 if (net_ratelimit())
1425 printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); 1445 printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
1426 addrconf_dad_stop(ifp); 1446 addrconf_dad_stop(ifp);
@@ -2753,6 +2773,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
2753 spin_lock_bh(&ifp->lock); 2773 spin_lock_bh(&ifp->lock);
2754 2774
2755 if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || 2775 if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
2776 idev->cnf.accept_dad < 1 ||
2756 !(ifp->flags&IFA_F_TENTATIVE) || 2777 !(ifp->flags&IFA_F_TENTATIVE) ||
2757 ifp->flags & IFA_F_NODAD) { 2778 ifp->flags & IFA_F_NODAD) {
2758 ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); 2779 ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
@@ -2800,6 +2821,11 @@ static void addrconf_dad_timer(unsigned long data)
2800 read_unlock_bh(&idev->lock); 2821 read_unlock_bh(&idev->lock);
2801 goto out; 2822 goto out;
2802 } 2823 }
2824 if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) {
2825 read_unlock_bh(&idev->lock);
2826 addrconf_dad_failure(ifp);
2827 return;
2828 }
2803 spin_lock_bh(&ifp->lock); 2829 spin_lock_bh(&ifp->lock);
2804 if (ifp->probes == 0) { 2830 if (ifp->probes == 0) {
2805 /* 2831 /*
@@ -3660,6 +3686,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
3660 array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; 3686 array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding;
3661#endif 3687#endif
3662 array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; 3688 array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
3689 array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
3663} 3690}
3664 3691
3665static inline size_t inet6_if_nlmsg_size(void) 3692static inline size_t inet6_if_nlmsg_size(void)
@@ -4227,6 +4254,14 @@ static struct addrconf_sysctl_table
4227 .proc_handler = &proc_dointvec, 4254 .proc_handler = &proc_dointvec,
4228 }, 4255 },
4229 { 4256 {
4257 .ctl_name = CTL_UNNUMBERED,
4258 .procname = "accept_dad",
4259 .data = &ipv6_devconf.accept_dad,
4260 .maxlen = sizeof(int),
4261 .mode = 0644,
4262 .proc_handler = &proc_dointvec,
4263 },
4264 {
4230 .ctl_name = 0, /* sentinel */ 4265 .ctl_name = 0, /* sentinel */
4231 } 4266 }
4232 }, 4267 },