Currently if you try to configure the same IPv6 address twice via the
SIOCAIFADDR_IN6 ioctl(2) the kernel will return EEXIST and the address
will be unset: 

# ifconfig vether0 inet6 2001::1
# ifconfig vether0 inet6 2001::1 
ifconfig: SIOCAIFADDR: File exists

Diff below fixes that by not inserting the local route if we're "just"
updating an existing address.  sebastia@ confirmed it fixes his use
case, so I'm looking for oks.

Index: netinet6/in6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/in6.c,v
retrieving revision 1.181
diff -u -p -r1.181 in6.c
--- netinet6/in6.c      3 Dec 2015 13:13:42 -0000       1.181
+++ netinet6/in6.c      18 Dec 2015 09:27:18 -0000
@@ -444,7 +444,7 @@ in6_control(struct socket *so, u_long cm
 
        case SIOCAIFADDR_IN6:
        {
-               int plen, error = 0;
+               int plen, error = 0, newifaddr = 0;
 
                /* reject read-only flags */
                if ((ifra->ifra_flags & IN6_IFF_DUPLICATED) != 0 ||
@@ -454,12 +454,15 @@ in6_control(struct socket *so, u_long cm
                        return (EINVAL);
                }
 
+               if (ia6 == NULL)
+                       newifaddr = 1;
+
                /*
                 * Make the address tentative before joining multicast
                 * addresses, so that corresponding MLD responses would
                 * not have a tentative source address.
                 */
-               if ((ia6 == NULL) && in6if_do_dad(ifp))
+               if (newifaddr && in6if_do_dad(ifp))
                        ifra->ifra_flags |= IN6_IFF_TENTATIVE;
 
                /*
@@ -477,8 +480,9 @@ in6_control(struct socket *so, u_long cm
                splx(s);
                if (error != 0)
                        return (error);
-               if ((ia6 = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
-                   == NULL) {
+
+               ia6 = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
+               if (ia6 == NULL) {
                        /*
                         * this can happen when the user specify the 0 valid
                         * lifetime.
@@ -489,6 +493,9 @@ in6_control(struct socket *so, u_long cm
                /* Perform DAD, if needed. */
                if (ia6->ia6_flags & IN6_IFF_TENTATIVE)
                        nd6_dad_start(&ia6->ia_ifa);
+
+               if (!newifaddr)
+                       break;
 
                plen = in6_mask2len(&ia6->ia_prefixmask.sin6_addr, NULL);
                if ((ifp->if_flags & IFF_LOOPBACK) || plen == 128) {

Reply via email to