]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Implement IPv6 static address, fixes [29417b793e].
authorRoy Marples <roy@marples.name>
Sun, 14 Feb 2016 08:04:55 +0000 (08:04 +0000)
committerRoy Marples <roy@marples.name>
Sun, 14 Feb 2016 08:04:55 +0000 (08:04 +0000)
dhcp6.c
dhcpcd.c
dhcpcd.conf.5.in
if-options.c
if-options.h
ipv6.c
ipv6.h
ipv6nd.c
script.c

diff --git a/dhcp6.c b/dhcp6.c
index 143de8458dc8d74961526dd8e496741e9716b0aa..2b13479fa727ba954b2ae8e6f38c5bd2cf85c85d 100644 (file)
--- a/dhcp6.c
+++ b/dhcp6.c
@@ -2431,7 +2431,7 @@ dhcp6_script_try_run(struct interface *ifp, int delegated)
                        continue;
                if (ap->flags & IPV6_AF_ONLINK) {
                        if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
-                           ipv6_iffindaddr(ap->iface, &ap->addr))
+                           ipv6_iffindaddr(ap->iface, &ap->addr, IN6_IFF_TENTATIVE))
                                ap->flags |= IPV6_AF_DADCOMPLETED;
                        if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0 &&
                            ((delegated && ap->delegating_iface) ||
index 4e37a681ac205608b6da5c9392d26c0f40eb07cf..78e08196c6b23cd07f43ef30cc5899567c74b1af 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -926,6 +926,8 @@ dhcpcd_startinterface(void *arg)
        }
 
        if (ifo->options & DHCPCD_IPV6) {
+               ipv6_startstatic(ifp);
+
                if (ifo->options & DHCPCD_IPV6RS)
                        ipv6nd_startrs(ifp);
 
index 9a7ad827b4bd9f1a239edc820cf9767cb6f8fd45..182fb101e728e2f704ed04780beccea8cd2aa5c4 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd February 5, 2016
+.Dd February 14, 2016
 .Dt DHCPCD.CONF 5
 .Os
 .Sh NAME
@@ -558,12 +558,25 @@ then
 .Nm dhcpcd
 will not attempt to obtain a lease and just use the value for the address with
 an infinite lease time.
+If you set
+.Ic ip6_address ,
+.Nm dhcpcd
+will continue auto-configuation as normal.
 .Pp
-Here is an example which configures a static address, routes and dns.
+Here is an example which configures two static addresss, an IPv4 router, DNS
+and disables IPv6 auto-configuration.
+You could also use the
+.Ic inform6
+command here if you wished to obtain more information via DHCPv6.
+For IPv4, you should use the
+.Ic inform Ar ipaddress
+option instead of setting a static address.
 .D1 interface eth0
+.D1 noipv6rs
 .D1 static ip_address=192.168.0.10/24
+.D1 static ip6_address=fd51:42f8:caae:d92e::ff/64
 .D1 static routers=192.168.0.1
-.D1 static domain_name_servers=192.168.0.1
+.D1 static domain_name_servers=192.168.0.1 fd51:42f8:caae:d92e::1
 .Pp
 Here is an example for PPP which gives the destination a default route.
 It uses the special destination keyword to insert the destination address
index 9097fa0d83e3fac429d716127780bdc24501fad5..57362f9dee544d93f36c19c8c42b813429229f9c 100644 (file)
@@ -1110,6 +1110,24 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
                                logger(ctx, LOG_ERR, "invalid MTU %s", p);
                                return -1;
                        }
+               } else if (strncmp(arg, "ip6_address=", strlen("ip6_address=")) == 0) {
+                       np = strchr(p, '/');
+                       if (np)
+                               *np++ = '\0';
+                       if (inet_pton(AF_INET6, p, &ifo->req_addr6) == 1) {
+                               if (np) {
+                                       ifo->req_prefix_len = (uint8_t)strtou(np,
+                                           NULL, 0, 0, 128, &e);
+                                       if (e) {
+                                               logger(ctx, LOG_ERR,
+                                                   "%s: failed to "
+                                                   "convert prefix len",
+                                                   ifname);
+                                               return -1;
+                                       }
+                               } else
+                                       ifo->req_prefix_len = 128;
+                       }
                } else {
                        dl = 0;
                        if (ifo->config != NULL) {
index 7d7e7c11cb68e34d2f0cfd62ba2d3ef8bc74e15e..d87096fd8da65e3b767780c93735ca55d9baf176 100644 (file)
@@ -176,6 +176,8 @@ struct if_options {
        struct in_addr req_addr;
        struct in_addr req_mask;
        struct rt_head *routes;
+       struct in6_addr req_addr6;
+       uint8_t req_prefix_len;
        unsigned int mtu;
        char **config;
 
diff --git a/ipv6.c b/ipv6.c
index 5c5f93e988ef02b577083ae2aeda7f184cd3f793..ee4f275f919abcfe7c9c2b9a0159b634cb4e629a 100644 (file)
--- a/ipv6.c
+++ b/ipv6.c
@@ -65,6 +65,7 @@
 #include "eloop.h"
 #include "ipv6.h"
 #include "ipv6nd.h"
+#include "script.h"
 
 #ifdef HAVE_MD5_H
 #  ifndef DEPGEN
 #  warning polling tentative address flags periodically
 #endif
 
-#ifdef __linux__
-   /* Match Linux defines to BSD */
-#  define IN6_IFF_TEMPORARY IFA_F_TEMPORARY
-#  ifdef IFA_F_OPTIMISTIC
-#    define IN6_IFF_TENTATIVE  (IFA_F_TENTATIVE | IFA_F_OPTIMISTIC)
-#  else
-#    define IN6_IFF_TENTATIVE   (IFA_F_TENTATIVE | 0x04)
-#  endif
-#  ifdef IF_F_DADFAILED
-#    define IN6_IFF_DUPLICATED IFA_F_DADFAILED
-#  else
-#    define IN6_IFF_DUPLICATED 0x08
-#  endif
-#  define IN6_IFF_DETACHED     0
-#endif
-
-#define IN6_IFF_NOTUSEABLE \
-       (IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED | IN6_IFF_DETACHED)
-
 /* Hackery at it's finest. */
 #ifndef s6_addr32
 #  ifdef __sun
@@ -382,7 +364,7 @@ ipv6_makestableprivate(struct in6_addr *addr,
 }
 
 int
-ipv6_makeaddr(struct in6_addr *addr, const struct interface *ifp,
+ipv6_makeaddr(struct in6_addr *addr, struct interface *ifp,
     const struct in6_addr *prefix, int prefix_len)
 {
        const struct ipv6_addr *ap;
@@ -647,7 +629,7 @@ ipv6_addaddr(struct ipv6_addr *ap, const struct timespec *now)
        }
 
        if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
-           ipv6_iffindaddr(ap->iface, &ap->addr))
+           ipv6_iffindaddr(ap->iface, &ap->addr, IN6_IFF_NOTUSEABLE))
                ap->flags |= IPV6_AF_DADCOMPLETED;
 
        logger(ap->iface->ctx, ap->flags & IPV6_AF_NEW ? LOG_INFO : LOG_DEBUG,
@@ -1039,7 +1021,7 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
                if (ap->addr_flags & IN6_IFF_TEMPORARY)
                        ap->flags |= IPV6_AF_TEMPORARY;
 #endif
-               if (IN6_IS_ADDR_LINKLOCAL(&ap->addr)) {
+               if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) || ap->dadcallback) {
 #ifdef IPV6_POLLADDRFLAG
                        if (ap->addr_flags & IN6_IFF_TENTATIVE) {
                                struct timespec tv;
@@ -1052,7 +1034,12 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
                        }
 #endif
 
-                       if (!(ap->addr_flags & IN6_IFF_NOTUSEABLE)) {
+                       if (ap->dadcallback)
+                               ap->dadcallback(ap);
+
+                       if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) &&
+                           !(ap->addr_flags & IN6_IFF_NOTUSEABLE))
+                       {
                                /* Now run any callbacks.
                                 * Typically IPv6RS or DHCPv6 */
                                while ((cb =
@@ -1081,22 +1068,23 @@ ipv6_hasaddr(const struct interface *ifp)
        return 0;
 }
 
-const struct ipv6_addr *
-ipv6_iffindaddr(const struct interface *ifp, const struct in6_addr *addr)
+struct ipv6_addr *
+ipv6_iffindaddr(struct interface *ifp, const struct in6_addr *addr,
+    int revflags)
 {
-       const struct ipv6_state *state;
-       const struct ipv6_addr *ap;
+       struct ipv6_state *state;
+       struct ipv6_addr *ap;
 
-       state = IPV6_CSTATE(ifp);
+       state = IPV6_STATE(ifp);
        if (state) {
                TAILQ_FOREACH(ap, &state->addrs, next) {
                        if (addr == NULL) {
                                if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) &&
-                                   !(ap->addr_flags & IN6_IFF_NOTUSEABLE))
+                                   (!revflags || !(ap->addr_flags & revflags)))
                                        return ap;
                        } else {
                                if (IN6_ARE_ADDR_EQUAL(&ap->addr, addr) &&
-                                   !(ap->addr_flags & IN6_IFF_TENTATIVE))
+                                   (!revflags || !(ap->addr_flags & revflags)))
                                        return ap;
                        }
                }
@@ -1295,39 +1283,146 @@ nextslaacprivate:
        return 1;
 }
 
-/* Ensure the interface has a link-local address */
-int
-ipv6_start(struct interface *ifp)
+static int
+ipv6_tryaddlinklocal(struct interface *ifp)
 {
-       const struct ipv6_state *state;
-       const struct ipv6_addr *ap;
 
        /* We can't assign a link-locak address to this,
         * the ppp process has to. */
        if (ifp->flags & IFF_POINTOPOINT)
                return 0;
 
-       state = IPV6_CSTATE(ifp);
-       if (state) {
-               TAILQ_FOREACH(ap, &state->addrs, next) {
-                       if (IN6_IS_ADDR_LINKLOCAL(&ap->addr) &&
-                           !(ap->addr_flags & IN6_IFF_DUPLICATED))
-                               break;
-               }
+       if (ipv6_iffindaddr(ifp, NULL, IN6_IFF_DUPLICATED) != NULL ||
+           !CAN_ADD_LLADDR(ifp))
+               return 0;
+
+       return ipv6_addlinklocal(ifp);
+}
+
+struct ipv6_addr *
+ipv6_newaddr(struct interface *ifp, struct in6_addr *addr, uint8_t prefix_len)
+{
+       struct ipv6_addr *ia;
+       char buf[INET6_ADDRSTRLEN];
+       const char *cbp;
+       struct ipv6_state *state;
+
+       if ((ia = calloc(1, sizeof(*ia))) == NULL)
+               return NULL;
+       ia->iface = ifp;
+       ia->flags = IPV6_AF_NEW;
+       ia->addr_flags = IN6_IFF_TENTATIVE;
+       ia->addr = *addr;
+       ia->prefix_len = prefix_len;
+       if (ipv6_makeprefix(&ia->prefix, &ia->addr, ia->prefix_len) == -1) {
+               free(ia);
+               return NULL;
+       }
+       cbp = inet_ntop(AF_INET6, &ia->addr, buf, sizeof(buf));
+       if (cbp)
+               snprintf(ia->saddr, sizeof(ia->saddr), "%s/%d",
+                   cbp, ia->prefix_len);
+       else
+               ia->saddr[0] = '\0';
+
+       state = IPV6_STATE(ifp);
+       TAILQ_INSERT_TAIL(&state->addrs, ia, next);
+       return ia;
+}
+
+static void
+ipv6_staticdadcallback(void *arg)
+{
+       struct ipv6_addr *ia = arg;
+       int wascompleted;
+
+       wascompleted = (ia->flags & IPV6_AF_DADCOMPLETED);
+       ia->flags |= IPV6_AF_DADCOMPLETED;
+       if (ia->flags & IPV6_AF_DUPLICATED)
+               logger(ia->iface->ctx, LOG_WARNING, "%s: DAD detected %s",
+                   ia->iface->name, ia->saddr);
+       else if (!wascompleted) {
+               logger(ia->iface->ctx, LOG_DEBUG, "%s: IPv6 static DAD completed",
+                   ia->iface->name);
+               script_runreason(ia->iface, "STATIC6");
+       }
+}
+
+ssize_t
+ipv6_env(char **env, const char *prefix, const struct interface *ifp)
+{
+       char **ep;
+       ssize_t n;
+       struct ipv6_addr *ia;
+
+       ep = env;
+       n = 0;
+       ia = ipv6_iffindaddr(UNCONST(ifp), &ifp->options->req_addr6, IN6_IFF_NOTUSEABLE);
+       if (ia) {
+               if (env)
+                       addvar(ifp->ctx, &ep, prefix, "ip6_address", ia->saddr);
+               n++;
+       }
+
+       return n;
+}
+
+int
+ipv6_startstatic(struct interface *ifp)
+{
+       struct ipv6_addr *ia;
+       int run_script;
+
+       if (IN6_IS_ADDR_UNSPECIFIED(&ifp->options->req_addr6))
+               return 0;
+
+       ia = ipv6_iffindaddr(ifp, &ifp->options->req_addr6, 0);
+       if (ia != NULL &&
+           (ia->prefix_len != ifp->options->req_prefix_len ||
+           ia->addr_flags & IN6_IFF_NOTUSEABLE))
+       {
+               ipv6_deleteaddr(ia);
+               ia = NULL;
+       }
+       if (ia == NULL) {
+               ia = ipv6_newaddr(ifp, &ifp->options->req_addr6,
+                   ifp->options->req_prefix_len);
+               if (ia == NULL)
+                       return -1;
+               run_script = 0;
+       } else
+               run_script = 1;
+       ia->flags |= IPV6_AF_STATIC | IPV6_AF_ONLINK;
+       ia->prefix_vltime = ND6_INFINITE_LIFETIME;
+       ia->prefix_pltime = ND6_INFINITE_LIFETIME;
+       ia->dadcallback = ipv6_staticdadcallback;
+       ipv6_addaddr(ia, NULL);
+       if_initrt6(ifp);
+       ipv6_buildroutes(ifp->ctx);
+       if (run_script)
+               script_runreason(ifp, "STATIC6");
+       return 1;
+}
+
+/* Ensure the interface has a link-local address */
+int
+ipv6_start(struct interface *ifp)
+{
+
+       if (ipv6_tryaddlinklocal(ifp) == -1)
+               return -1;
+
+       if (IPV6_CSTATE(ifp)) {
                /* Regenerate new ids */
                if (ifp->options->options & DHCPCD_IPV6RA_OWN &&
                    ip6_use_tempaddr(ifp->name))
                        ipv6_regentempifid(ifp);
-       } else
-               ap = NULL;
-
-       if (ap == NULL &&
-           CAN_ADD_LLADDR(ifp) &&
-           ipv6_addlinklocal(ifp) == -1)
-               return -1;
+       }
 
        /* Load existing routes */
        if_initrt6(ifp);
+       if (!IN6_IS_ADDR_UNSPECIFIED(&ifp->options->req_addr6))
+               ipv6_buildroutes(ifp->ctx);
        return 0;
 }
 
@@ -1344,10 +1439,12 @@ ipv6_freedrop(struct interface *ifp, int drop)
                return;
 
        ipv6_freedrop_addrs(&state->addrs, drop ? 2 : 0, NULL);
-
-       /* Because we need to cache the addresses we don't control,
-        * we only free the state on when NOT dropping addresses. */
-       if (drop == 0) {
+       if (drop) {
+               if_initrt6(ifp);
+               ipv6_buildroutes(ifp->ctx);
+       } else {
+               /* Because we need to cache the addresses we don't control,
+                * we only free the state on when NOT dropping addresses. */
                while ((cb = TAILQ_FIRST(&state->ll_callbacks))) {
                        TAILQ_REMOVE(&state->ll_callbacks, cb, next);
                        free(cb);
@@ -2063,6 +2160,29 @@ make_router(const struct ra *rap)
        (IN6_ARE_ADDR_EQUAL(&((rtp)->dest), &in6addr_any) &&                  \
            IN6_ARE_ADDR_EQUAL(&((rtp)->net), &in6addr_any))
 
+static void
+ipv6_build_static_routes(struct dhcpcd_ctx *ctx, struct rt6_head *dnr)
+{
+       const struct interface *ifp;
+       const struct ipv6_state *state;
+       const struct ipv6_addr *ia;
+       struct rt6 *rt;
+
+       TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+               if ((state = IPV6_CSTATE(ifp)) == NULL)
+                       continue;
+               TAILQ_FOREACH(ia, &state->addrs, next) {
+                       if ((ia->flags & (IPV6_AF_ADDED | IPV6_AF_STATIC)) ==
+                           (IPV6_AF_ADDED | IPV6_AF_STATIC))
+                       {
+                               rt = make_prefix(ifp, NULL, ia);
+                               if (rt)
+                                       TAILQ_INSERT_TAIL(dnr, rt, next);
+                       }
+               }
+       }
+}
+
 static void
 ipv6_build_ra_routes(struct ipv6_ctx *ctx, struct rt6_head *dnr, int expired)
 {
@@ -2126,6 +2246,9 @@ ipv6_buildroutes(struct dhcpcd_ctx *ctx)
 
        TAILQ_INIT(&dnr);
 
+       /* Should static take priority? */
+       ipv6_build_static_routes(ctx, &dnr);
+
        /* First add reachable routers and their prefixes */
        ipv6_build_ra_routes(ctx->ipv6, &dnr, 0);
 #ifdef HAVE_ROUTE_METRIC
diff --git a/ipv6.h b/ipv6.h
index 031610fba73dbc3182894c636af3369269a5f79a..a02f102abc9e560efa5d038efc4449b576e100e8 100644 (file)
--- a/ipv6.h
+++ b/ipv6.h
 #define IPV6_MANAGETEMPADDR
 #endif
 
+#ifdef __linux__
+   /* Match Linux defines to BSD */
+#  define IN6_IFF_TEMPORARY IFA_F_TEMPORARY
+#  ifdef IFA_F_OPTIMISTIC
+#    define IN6_IFF_TENTATIVE  (IFA_F_TENTATIVE | IFA_F_OPTIMISTIC)
+#  else
+#    define IN6_IFF_TENTATIVE   (IFA_F_TENTATIVE | 0x04)
+#  endif
+#  ifdef IF_F_DADFAILED
+#    define IN6_IFF_DUPLICATED IFA_F_DADFAILED
+#  else
+#    define IN6_IFF_DUPLICATED 0x08
+#  endif
+#  define IN6_IFF_DETACHED     0
+#endif
+
+#define IN6_IFF_NOTUSEABLE \
+       (IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED | IN6_IFF_DETACHED)
+
 struct ipv6_addr {
        TAILQ_ENTRY(ipv6_addr) next;
        struct interface *iface;
@@ -157,8 +176,9 @@ TAILQ_HEAD(ipv6_addrhead, ipv6_addr);
 #define IPV6_AF_DELEGATEDPFX   0x0100
 #define IPV6_AF_DELEGATEDZERO  0x0200
 #define IPV6_AF_REQUEST                0x0400
+#define IPV6_AF_STATIC         0x0800
 #ifdef IPV6_MANAGETEMPADDR
-#define IPV6_AF_TEMPORARY      0X0800
+#define IPV6_AF_TEMPORARY      0X1000
 #endif
 
 struct rt6 {
@@ -244,7 +264,7 @@ struct ipv6_ctx *ipv6_init(struct dhcpcd_ctx *);
 int ipv6_makestableprivate(struct in6_addr *addr,
     const struct in6_addr *prefix, int prefix_len,
     const struct interface *ifp, int *dad_counter);
-int ipv6_makeaddr(struct in6_addr *, const struct interface *,
+int ipv6_makeaddr(struct in6_addr *, struct interface *,
     const struct in6_addr *, int);
 int ipv6_makeprefix(struct in6_addr *, const struct in6_addr *, int);
 int ipv6_mask(struct in6_addr *, int);
@@ -261,8 +281,9 @@ void ipv6_handleifa(struct dhcpcd_ctx *ctx, int, struct if_head *,
 int ipv6_handleifa_addrs(int, struct ipv6_addrhead *,
     const struct in6_addr *, int);
 int ipv6_publicaddr(const struct ipv6_addr *);
-const struct ipv6_addr *ipv6_iffindaddr(const struct interface *,
-    const struct in6_addr *);
+struct ipv6_addr *ipv6_newaddr(struct interface *, struct in6_addr *, uint8_t);
+struct ipv6_addr *ipv6_iffindaddr(struct interface *,
+    const struct in6_addr *, int);
 int ipv6_hasaddr(const struct interface *);
 int ipv6_findaddrmatch(const struct ipv6_addr *, const struct in6_addr *,
     short);
@@ -270,7 +291,7 @@ struct ipv6_addr *ipv6_findaddr(struct dhcpcd_ctx *,
     const struct in6_addr *, short);
 struct ipv6_addr *ipv6_findmaskaddr(struct dhcpcd_ctx *,
     const struct in6_addr *);
-#define ipv6_linklocal(ifp) ipv6_iffindaddr((ifp), NULL)
+#define ipv6_linklocal(ifp) ipv6_iffindaddr((ifp), NULL, IN6_IFF_NOTUSEABLE)
 int ipv6_addlinklocalcallback(struct interface *, void (*)(void *), void *);
 void ipv6_freeaddr(struct ipv6_addr *);
 void ipv6_freedrop(struct interface *, int);
@@ -290,6 +311,8 @@ void ipv6_addtempaddrs(struct interface *, const struct timespec *);
 #endif
 
 int ipv6_start(struct interface *);
+int ipv6_startstatic(struct interface *);
+ssize_t ipv6_env(char **, const char *, const struct interface *);
 void ipv6_ctxfree(struct dhcpcd_ctx *);
 int ipv6_handlert(struct dhcpcd_ctx *, int cmd, struct rt6 *);
 void ipv6_freerts(struct rt6_head *);
@@ -298,6 +321,7 @@ void ipv6_buildroutes(struct dhcpcd_ctx *);
 #else
 #define ipv6_init(a) (NULL)
 #define ipv6_start(a) (-1)
+#define ipv6_startstatic(a) (0)
 #define ipv6_hasaddr(a) (0)
 #define ipv6_free_ll_callbacks(a) {}
 #define ipv6_free(a) {}
index 78be3b0b00d3c3fe0101d03198e3d98027f9e7ac..43df4090e024ae0a686b7226e6dfc11a6dd70690 100644 (file)
--- a/ipv6nd.c
+++ b/ipv6nd.c
@@ -551,7 +551,7 @@ ipv6nd_scriptrun(struct ra *rap)
                {
                        hasaddress = 1;
                        if (!(ap->flags & IPV6_AF_DADCOMPLETED) &&
-                           ipv6_iffindaddr(ap->iface, &ap->addr))
+                           ipv6_iffindaddr(ap->iface, &ap->addr, IN6_IFF_TENTATIVE))
                                ap->flags |= IPV6_AF_DADCOMPLETED;
                        if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
                                logger(ap->iface->ctx, LOG_DEBUG,
@@ -798,7 +798,7 @@ ipv6nd_handlera(struct dhcpcd_ctx *dctx, struct interface *ifp,
                return;
        }
 
-       if (ipv6_iffindaddr(ifp, &ctx->from.sin6_addr)) {
+       if (ipv6_iffindaddr(ifp, &ctx->from.sin6_addr, IN6_IFF_TENTATIVE)) {
                logger(ifp->ctx, LOG_DEBUG,
                    "%s: ignoring RA from ourself %s", ifp->name, ctx->sfrom);
                return;
index 44bfed9b3ca7aeda3a56faa1e453ef81cc4c2188..6909f187ae70ac4504f8d7a73892b73fe0813ef5 100644 (file)
--- a/script.c
+++ b/script.c
@@ -240,7 +240,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
 #endif
 #ifdef INET6
        const struct dhcp6_state *d6_state;
-       int dhcp6, ra;
+       int static6, dhcp6, ra;
 #endif
 
 #ifdef INET
@@ -249,7 +249,7 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
        istate = IPV4LL_CSTATE(ifp);
 #endif
 #ifdef INET6
-       dhcp6 = ra = 0;
+       static6 = dhcp6 = ra = 0;
        d6_state = D6_CSTATE(ifp);
 #endif
        if (strcmp(reason, "TEST") == 0) {
@@ -268,6 +268,8 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
 #endif
        }
 #ifdef INET6
+       else if (strcmp(reason, "STATIC6") == 0)
+               static6 = 1;
        else if (reason[strlen(reason) - 1] == '6')
                dhcp6 = 1;
        else if (strcmp(reason, "ROUTERADVERT") == 0)
@@ -492,6 +494,20 @@ dumplease:
        }
 #endif
 #ifdef INET6
+       if (static6) {
+               n = ipv6_env(NULL, NULL, ifp);
+               if (n > 0) {
+                       nenv = realloc(env, sizeof(char *) *
+                           (elen + (size_t)n + 1));
+                       if (nenv == NULL)
+                               goto eexit;
+                       env = nenv;
+                       n = ipv6_env(env + elen, "new", ifp);
+                       if (n == -1)
+                               goto eexit;
+                       elen += (size_t)n;
+               }
+       }
        if (dhcp6 && D6_STATE_RUNNING(ifp)) {
                n = dhcp6_env(NULL, NULL, ifp,
                    d6_state->new, d6_state->new_len);