Now that the dust has settled a bit, I'd like to simplify in6_ioctl() a
bit more. At the moment it still has two tangled switches that deal with
SIOCAIFADDR_IN6 and SIOCDIFADDR_IN6. We can disentangle them at the cost
of repeating a few lines, but I think it's worth it.

I also introduced another function to make in6_ioctl() appear a bit more
symmetric.

Index: sys/netinet6/in6.c
===================================================================
RCS file: /var/cvs/src/sys/netinet6/in6.c,v
retrieving revision 1.224
diff -u -p -r1.224 in6.c
--- sys/netinet6/in6.c  4 May 2018 19:43:07 -0000       1.224
+++ sys/netinet6/in6.c  5 May 2018 12:21:41 -0000
@@ -116,6 +116,7 @@ const struct in6_addr in6mask96 = IN6MAS
 const struct in6_addr in6mask128 = IN6MASK128;
 
 int in6_ioctl(u_long, caddr_t, struct ifnet *, int);
+int in6_ioctl_change_ifaddr(u_long, caddr_t, struct ifnet *);
 int in6_ioctl_get(u_long, caddr_t, struct ifnet *);
 int in6_ifinit(struct ifnet *, struct in6_ifaddr *, int);
 void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *);
@@ -206,12 +207,6 @@ in6_control(struct socket *so, u_long cm
 int
 in6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged)
 {
-       struct  in6_ifreq *ifr = (struct in6_ifreq *)data;
-       struct  in6_ifaddr *ia6 = NULL;
-       struct  in6_aliasreq *ifra = (struct in6_aliasreq *)data;
-       struct sockaddr_in6 *sa6;
-       int     error = 0;
-
        if (ifp == NULL)
                return (ENXIO);
 
@@ -225,11 +220,10 @@ in6_ioctl(u_long cmd, caddr_t data, stru
        case SIOCGIFALIFETIME_IN6:
                return (in6_ioctl_get(cmd, data, ifp));
        case SIOCAIFADDR_IN6:
-               sa6 = &ifra->ifra_addr;
-               break;
        case SIOCDIFADDR_IN6:
-               sa6 = &ifr->ifr_addr;
-               break;
+               if (!privileged)
+                       return (EPERM);
+               return (in6_ioctl_change_ifaddr(cmd, data, ifp));
        case SIOCSIFADDR:
        case SIOCSIFDSTADDR:
        case SIOCSIFBRDADDR:
@@ -242,6 +236,16 @@ in6_ioctl(u_long cmd, caddr_t data, stru
        default:
                return (EOPNOTSUPP);
        }
+}
+
+int
+in6_ioctl_change_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp)
+{
+       struct  in6_ifreq *ifr = (struct in6_ifreq *)data;
+       struct  in6_ifaddr *ia6 = NULL;
+       struct  in6_aliasreq *ifra = (struct in6_aliasreq *)data;
+       struct sockaddr_in6 *sa6;
+       int     error = 0, newifaddr = 0, plen;
 
        /*
         * Find address for this interface, if it exists.
@@ -255,6 +259,16 @@ in6_ioctl(u_long cmd, caddr_t data, stru
         * presence of ifra_addr, and reject invalid ones here.
         * It also decreases duplicated code among SIOC*_IN6 operations.
         */
+       switch(cmd) {
+       case SIOCAIFADDR_IN6:
+               sa6 = &ifra->ifra_addr;
+               break;
+       case SIOCDIFADDR_IN6:
+               sa6 = &ifr->ifr_addr;
+               break;
+       default:
+               panic("unknown ioctl %lu", cmd);
+       }
 
        NET_LOCK();
 
@@ -279,8 +293,7 @@ in6_ioctl(u_long cmd, caddr_t data, stru
                        }
                }
                ia6 = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
-       } else
-               ia6 = NULL;
+       }
 
        switch (cmd) {
        case SIOCDIFADDR_IN6:
@@ -293,10 +306,8 @@ in6_ioctl(u_long cmd, caddr_t data, stru
                 */
                if (ia6 == NULL) {
                        error = EADDRNOTAVAIL;
-                       goto err;
+                       break;
                }
-               /* FALLTHROUGH */
-       case SIOCAIFADDR_IN6:
                /*
                 * We always require users to specify a valid IPv6 address for
                 * the corresponding operation.
@@ -304,19 +315,22 @@ in6_ioctl(u_long cmd, caddr_t data, stru
                if (ifra->ifra_addr.sin6_family != AF_INET6 ||
                    ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) {
                        error = EAFNOSUPPORT;
-                       goto err;
-               }
-               if (!privileged) {
-                       error = EPERM;
-                       goto err;
+                       break;
                }
+               in6_purgeaddr(&ia6->ia_ifa);
+               dohooks(ifp->if_addrhooks, 0);
                break;
-       }
 
-       switch (cmd) {
        case SIOCAIFADDR_IN6:
-       {
-               int plen, newifaddr = 0;
+               /*
+                * We always require users to specify a valid IPv6 address for
+                * the corresponding operation.
+                */
+               if (ifra->ifra_addr.sin6_family != AF_INET6 ||
+                   ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) {
+                       error = EAFNOSUPPORT;
+                       break;
+               }
 
                /* reject read-only flags */
                if ((ifra->ifra_flags & IN6_IFF_DUPLICATED) != 0 ||
@@ -379,12 +393,6 @@ in6_ioctl(u_long cmd, caddr_t data, stru
                        in6_purgeaddr(&ia6->ia_ifa);
                        break;
                }
-               dohooks(ifp->if_addrhooks, 0);
-               break;
-       }
-
-       case SIOCDIFADDR_IN6:
-               in6_purgeaddr(&ia6->ia_ifa);
                dohooks(ifp->if_addrhooks, 0);
                break;
        }

Reply via email to