When adding an IPv6 address to a given interface, I'm allowed to add that address multiple times. Following is a patch attempting to fix this bug. It's for 2.4.20 but sould apply cleanly on 2.5 too. --- net/ipv6/addrconf.c.orig 2003-03-25 21:33:55.000000000 +0100 +++ net/ipv6/addrconf.c 2003-03-30 13:48:23.000000000 +0200 @@ -89,6 +89,8 @@ static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE]; static rwlock_t addrconf_hash_lock = RW_LOCK_UNLOCKED; +static spinlock_t addrconf_add_lock = SPIN_LOCK_UNLOCKED; + /* Protects inet6 devices */ rwlock_t addrconf_lock = RW_LOCK_UNLOCKED; @@ -621,6 +623,24 @@ return ifp != NULL; } +static struct inet6_ifaddr * +ipv6_addr_already_present(struct in6_addr *addr, struct net_device *dev) +{ + struct inet6_ifaddr *ifp; + u8 hash = ipv6_addr_hash(addr); + + read_lock_bh(&addrconf_hash_lock); + for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) { + if (ipv6_addr_cmp(&ifp->addr, addr) == 0 && ifp->idev->dev == dev) { + read_unlock_bh(&addrconf_hash_lock); + return ifp; + } + } + read_unlock_bh(&addrconf_hash_lock); + return NULL; +} + + struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, struct net_device *dev) { struct inet6_ifaddr * ifp; @@ -908,7 +928,7 @@ return; ok: - + spin_lock_bh(&addrconf_add_lock); ifp = ipv6_get_ifaddr(&addr, dev); if (ifp == NULL && valid_lft) { @@ -920,12 +940,14 @@ addr_type&IPV6_ADDR_SCOPE_MASK, 0); if (ifp == NULL) { + spin_unlock_bh(&addrconf_add_lock); in6_dev_put(in6_dev); return; } addrconf_dad_start(ifp); } + spin_unlock_bh(&addrconf_add_lock); if (ifp && valid_lft == 0) { ipv6_del_addr(ifp); @@ -1033,11 +1055,19 @@ scope = ipv6_addr_scope(pfx); + spin_lock_bh(&addrconf_add_lock); + if (ipv6_addr_already_present(pfx, dev)) { + spin_unlock_bh(&addrconf_add_lock); + return -EEXIST; + } + if ((ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT)) != NULL) { + spin_unlock_bh(&addrconf_add_lock); addrconf_dad_start(ifp); in6_ifa_put(ifp); return 0; } + spin_unlock_bh(&addrconf_add_lock); return -ENOBUFS; }