#include <linux/errno.h>
#include <linux/types.h>
+#include <linux/kernel.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/net.h>
{
struct inet6_ifaddr *ifa = NULL;
struct rt6_info *rt;
+ struct net *net = dev_net(idev->dev);
int hash;
int err = 0;
int addr_type = ipv6_addr_type(addr);
goto out2;
}
+ if (idev->cnf.disable_ipv6 || net->ipv6.devconf_all->disable_ipv6) {
+ err = -EACCES;
+ goto out2;
+ }
+
write_lock(&addrconf_hash_lock);
/* Ignore adding duplicate addresses on an interface */
}
break;
} else if (minihiscore < miniscore) {
- struct ipv6_saddr_score *tmp;
-
if (hiscore->ifa)
in6_ifa_put(hiscore->ifa);
in6_ifa_hold(score->ifa);
- tmp = hiscore;
- hiscore = score;
- score = tmp;
+ swap(hiscore, score);
/* restore our iterator */
score->ifa = hiscore->ifa;
return ifp;
}
-int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
-{
- const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
- const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2);
- __be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr;
- __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
- int sk_ipv6only = ipv6_only_sock(sk);
- int sk2_ipv6only = inet_v6_ipv6only(sk2);
- int addr_type = ipv6_addr_type(sk_rcv_saddr6);
- int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED;
-
- if (!sk2_rcv_saddr && !sk_ipv6only)
- return 1;
-
- if (addr_type2 == IPV6_ADDR_ANY &&
- !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED))
- return 1;
-
- if (addr_type == IPV6_ADDR_ANY &&
- !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED))
- return 1;
-
- if (sk2_rcv_saddr6 &&
- ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6))
- return 1;
-
- if (addr_type == IPV6_ADDR_MAPPED &&
- !sk2_ipv6only &&
- (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr))
- return 1;
-
- return 0;
-}
-
/* Gets referenced address, destroys ifaddr */
static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
void addrconf_dad_failure(struct inet6_ifaddr *ifp)
{
struct inet6_dev *idev = ifp->idev;
+
+ if (net_ratelimit())
+ printk(KERN_INFO "%s: IPv6 duplicate address detected!\n",
+ ifp->idev->dev->name);
+
if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) {
struct in6_addr addr;
ipv6_addr_equal(&ifp->addr, &addr)) {
/* DAD failed for link-local based on MAC address */
idev->cnf.disable_ipv6 = 1;
+
+ printk(KERN_INFO "%s: IPv6 being disabled!\n",
+ ifp->idev->dev->name);
}
}
- if (net_ratelimit())
- printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
addrconf_dad_stop(ifp);
}
read_unlock_bh(&idev->lock);
goto out;
}
- if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) {
- read_unlock_bh(&idev->lock);
- addrconf_dad_failure(ifp);
- return;
- }
spin_lock_bh(&ifp->lock);
if (ifp->probes == 0) {
/*