Merge branches 'master' and 'suser_to_priv'
[dragonfly.git] / sys / netinet / in.c
index e802bb8..8693d69 100644 (file)
@@ -42,6 +42,7 @@
 #include <sys/sockio.h>
 #include <sys/malloc.h>
 #include <sys/proc.h>
+#include <sys/priv.h>
 #include <sys/msgport.h>
 #include <sys/socket.h>
 
@@ -230,7 +231,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
        switch (cmd) {
        case SIOCALIFADDR:
        case SIOCDLIFADDR:
-               if (td && (error = suser(td)) != 0)
+               if (td && (error = priv_check(td, PRIV_ROOT)) != 0)
                        return error;
                /* FALLTHROUGH */
        case SIOCGLIFADDR:
@@ -454,10 +455,11 @@ in_control_internal(u_long cmd, caddr_t data, struct ifnet *ifp,
        struct ifaddr_container *ifac;
        struct in_ifaddr_container *iac;
        struct sockaddr_in oldaddr;
-       int hostIsNew, iaIsNew, maskIsNew;
+       int hostIsNew, iaIsNew, maskIsNew, ifpWasUp;
        int error = 0;
 
        iaIsNew = 0;
+       ifpWasUp = 0;
 
        /*
         * Find address for this interface, if it exists.
@@ -487,6 +489,9 @@ in_control_internal(u_long cmd, caddr_t data, struct ifnet *ifp,
                                }
                        }
                }
+
+               if (ifp->if_flags & IFF_UP)
+                       ifpWasUp = 1;
        }
 
        switch (cmd) {
@@ -514,7 +519,7 @@ in_control_internal(u_long cmd, caddr_t data, struct ifnet *ifp,
        case SIOCSIFADDR:
        case SIOCSIFNETMASK:
        case SIOCSIFDSTADDR:
-               if (td && (error = suser(td)) != 0)
+               if (td && (error = priv_check(td, PRIV_ROOT)) != 0)
                        return error;
 
                if (ifp == NULL)
@@ -569,7 +574,7 @@ in_control_internal(u_long cmd, caddr_t data, struct ifnet *ifp,
                break;
 
        case SIOCSIFBRDADDR:
-               if (td && (error = suser(td)) != 0)
+               if (td && (error = priv_check(td, PRIV_ROOT)) != 0)
                        return error;
                /* FALLTHROUGH */
 
@@ -643,6 +648,14 @@ in_control_internal(u_long cmd, caddr_t data, struct ifnet *ifp,
                        iaIsNew ? IFADDR_EVENT_ADD : IFADDR_EVENT_CHANGE,
                        &ia->ia_ifa);
                }
+               if (!ifpWasUp && (ifp->if_flags & IFF_UP)) {
+                       /*
+                        * Interface is brought up by in_ifinit()
+                        * (via ifp->if_ioctl).  We act as if the
+                        * interface got IFF_UP flag turned on.
+                        */
+                       if_up(ifp);
+               }
                return (0);
 
        case SIOCSIFNETMASK:
@@ -692,6 +705,10 @@ in_control_internal(u_long cmd, caddr_t data, struct ifnet *ifp,
                        iaIsNew ? IFADDR_EVENT_ADD : IFADDR_EVENT_CHANGE,
                        &ia->ia_ifa);
                }
+               if (!ifpWasUp && (ifp->if_flags & IFF_UP)) {
+                       /* See the comment in SIOCSIFADDR */
+                       if_up(ifp);
+               }
                return (error);
 
        case SIOCDIFADDR:
@@ -747,6 +764,24 @@ in_control_internal(u_long cmd, caddr_t data, struct ifnet *ifp,
 
        ifa_destroy(&ia->ia_ifa);
 
+       if ((cmd == SIOCAIFADDR || cmd == SIOCSIFADDR) &&
+           !ifpWasUp && (ifp->if_flags & IFF_UP)) {
+               /*
+                * Though the address assignment failed, the
+                * interface is brought up by in_ifinit()
+                * (via ifp->if_ioctl).  With the hope that
+                * the interface has some valid addresses, we
+                * act as if IFF_UP flag was just set on the
+                * interface.
+                *
+                * NOTE:
+                * This could only be done after the failed
+                * address is unlinked from the global address
+                * list.
+                */
+               if_up(ifp);
+       }
+
        return (error);
 }