]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Allow the request of a DHCPv6 address or prefix, a prefix length must be specified.
authorRoy Marples <roy@marples.name>
Sat, 21 Jun 2014 11:42:36 +0000 (11:42 +0000)
committerRoy Marples <roy@marples.name>
Sat, 21 Jun 2014 11:42:36 +0000 (11:42 +0000)
dhcp6.c
dhcpcd.conf.5.in
if-options.c
if-options.h
ipv6.h

diff --git a/dhcp6.c b/dhcp6.c
index ad439fd2f6521b57ed8fcd16dbeb2197384fd3f7..96fcd417c06c13fbb5ba734f050f2c9d855817aa 100644 (file)
--- a/dhcp6.c
+++ b/dhcp6.c
@@ -405,12 +405,15 @@ dhcp6_makemessage(struct interface *ifp)
        case DH6S_REBIND:
                /* FALLTHROUGH */
        case DH6S_CONFIRM:
+               /* FALLTHROUGH */
+       case DH6S_DISCOVER:
                if (m == NULL) {
                        m = state->new;
                        ml = state->new_len;
                }
                TAILQ_FOREACH(ap, &state->addrs, next) {
-                       if (ap->prefix_vltime == 0)
+                       if (ap->prefix_vltime == 0 &&
+                           !(ap->flags & IPV6_AF_REQUEST))
                                continue;
                        if (ifo->ia_type == D6_OPTION_IA_PD)
                                len += sizeof(*o) + sizeof(u8) +
@@ -421,8 +424,7 @@ dhcp6_makemessage(struct interface *ifp)
                                    sizeof(u32) + sizeof(u32);
                }
                /* FALLTHROUGH */
-       case DH6S_INIT: /* FALLTHROUGH */
-       case DH6S_DISCOVER:
+       case DH6S_INIT:
                len += ifo->ia_len * (sizeof(*o) + (sizeof(u32) * 3));
                IA = 1;
                break;
@@ -536,7 +538,8 @@ dhcp6_makemessage(struct interface *ifp)
                p += sizeof(u32);
                memset(p, 0, sizeof(u32) + sizeof(u32));
                TAILQ_FOREACH(ap, &state->addrs, next) {
-                       if (ap->prefix_vltime == 0)
+                       if (ap->prefix_vltime == 0 &&
+                           !(ap->flags & IPV6_AF_REQUEST))
                                continue;
                        if (memcmp(ifo->ia[l].iaid, ap->iaid, sizeof(u32)))
                                continue;
@@ -948,11 +951,52 @@ dhcp6_startrenew(void *arg)
                dhcp6_sendrenew(ifp);
 }
 
+static void
+dhcp6_dadcallback(void *arg)
+{
+       struct ipv6_addr *ap = arg;
+       struct interface *ifp;
+       struct dhcp6_state *state;
+       int wascompleted;
+
+       wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
+       ap->flags |= IPV6_AF_DADCOMPLETED;
+       if (ap->flags & IPV6_AF_DUPLICATED)
+               /* XXX FIXME
+                * We should decline the address */
+               syslog(LOG_WARNING, "%s: DAD detected %s",
+                   ap->iface->name, ap->saddr);
+
+       if (!wascompleted) {
+               ifp = ap->iface;
+               state = D6_STATE(ifp);
+               if (state->state == DH6S_BOUND ||
+                   state->state == DH6S_DELEGATED)
+               {
+                       TAILQ_FOREACH(ap, &state->addrs, next) {
+                               if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
+                                       wascompleted = 1;
+                                       break;
+                               }
+                       }
+                       if (!wascompleted) {
+                               syslog(LOG_DEBUG, "%s: DHCPv6 DAD completed",
+                                   ifp->name);
+                               script_runreason(ifp, state->reason);
+                               dhcpcd_daemonise(ifp->ctx);
+                       }
+               }
+       }
+}
+
 static void
 dhcp6_startdiscover(void *arg)
 {
        struct interface *ifp;
        struct dhcp6_state *state;
+       size_t i;
+       struct if_ia *ia;
+       struct ipv6_addr *a;
 
        ifp = arg;
        dhcp6_delete_delegates(ifp);
@@ -974,6 +1018,30 @@ dhcp6_startdiscover(void *arg)
        dhcp6_freedrop_addrs(ifp, 0, NULL);
        unlink(state->leasefile);
 
+       /* Add any requested prefixes / addresses */
+       for (i = 0; i < ifp->options->ia_len; i++) {
+               ia = &ifp->options->ia[i];
+               if (ia->prefix_len) {
+                       a = calloc(1, sizeof(*a));
+                       if (a == NULL) {
+                               syslog(LOG_ERR, "%s: %m", __func__);
+                               return NULL;
+                       }
+                       a->flags = IPV6_AF_REQUEST;
+                       a->iface = ifp;
+                       a->dadcallback = dhcp6_dadcallback;
+                       memcpy(&a->iaid, &ia->iaid, sizeof(a->iaid));
+                       //a->prefix_pltime = 0;
+                       //a->prefix_vltime = 0;
+                       if (ifp->options->ia_type == D6_OPTION_IA_PD)
+                               memcpy(&a->prefix, &ia->addr, sizeof(a->addr));
+                       else
+                               memcpy(&a->addr, &ia->addr, sizeof(a->addr));
+                       a->prefix_len = ia->prefix_len;
+                       TAILQ_INSERT_TAIL(&state->addrs, a, next);
+               }
+       }
+
        if (dhcp6_makemessage(ifp) == -1)
                syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
        else
@@ -1264,44 +1332,6 @@ dhcp6_addrexists(struct dhcpcd_ctx *ctx, const struct ipv6_addr *addr)
        return 0;
 }
 
-static void
-dhcp6_dadcallback(void *arg)
-{
-       struct ipv6_addr *ap = arg;
-       struct interface *ifp;
-       struct dhcp6_state *state;
-       int wascompleted;
-
-       wascompleted = (ap->flags & IPV6_AF_DADCOMPLETED);
-       ap->flags |= IPV6_AF_DADCOMPLETED;
-       if (ap->flags & IPV6_AF_DUPLICATED)
-               /* XXX FIXME
-                * We should decline the address */
-               syslog(LOG_WARNING, "%s: DAD detected %s",
-                   ap->iface->name, ap->saddr);
-
-       if (!wascompleted) {
-               ifp = ap->iface;
-               state = D6_STATE(ifp);
-               if (state->state == DH6S_BOUND ||
-                   state->state == DH6S_DELEGATED)
-               {
-                       TAILQ_FOREACH(ap, &state->addrs, next) {
-                               if ((ap->flags & IPV6_AF_DADCOMPLETED) == 0) {
-                                       wascompleted = 1;
-                                       break;
-                               }
-                       }
-                       if (!wascompleted) {
-                               syslog(LOG_DEBUG, "%s: DHCPv6 DAD completed",
-                                   ifp->name);
-                               script_runreason(ifp, state->reason);
-                               dhcpcd_daemonise(ifp->ctx);
-                       }
-               }
-       }
-}
-
 static int
 dhcp6_findna(struct interface *ifp, const uint8_t *iaid,
     const uint8_t *d, size_t l)
@@ -1370,7 +1400,7 @@ dhcp6_findna(struct interface *ifp, const uint8_t *iaid,
                            "%s/%d", ia, a->prefix_len);
                        TAILQ_INSERT_TAIL(&state->addrs, a, next);
                } else
-                       a->flags &= ~IPV6_AF_STALE;
+                       a->flags &= ~(IPV6_AF_STALE | IPV6_AF_REQUEST);
                memcpy(&u32, p, sizeof(u32));
                a->prefix_pltime = ntohl(u32);
                p += sizeof(u32);
@@ -1455,7 +1485,7 @@ dhcp6_findpd(struct interface *ifp, const uint8_t *iaid,
                            "%s/%d", ia, a->prefix_len);
                        TAILQ_INSERT_TAIL(&state->addrs, a, next);
                } else {
-                       a->flags &= ~IPV6_AF_STALE;
+                       a->flags &= ~(IPV6_AF_STALE | IPV6_AF_REQUEST);
                        if (a->prefix_vltime != vltime)
                                a->flags |= IPV6_AF_NEW;
                }
index d53e8285df8e81c1858d13490cba60cb05a1da3f..d755e678b0125d33b441003433e06610c79343c0 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd June 6, 2014
+.Dd June 20, 2014
 .Dt DHCPCD.CONF 5
 .Os
 .Sh NAME
@@ -214,7 +214,7 @@ DNS if the domain part does not match theirs.
 Also, see the
 .Ic env
 option above to control how the hostname is set on the host.
-.It Ic ia_na Op Ar iaid
+.It Ic ia_na Op Ar iaid Op / address Op / prefix_len
 Request a DHCPv6 Normal Address for
 .Ar iaid .
 .Ar iaid
@@ -230,7 +230,7 @@ Request a DHCPv6 Temporary Address for
 You can request more than one ia_ta by specifying a unique
 .Ar iaid
 for each one.
-.It Ic ia_pd Op Ar iaid Op Ar interface Op / Ar sla_id Op / Ar prefix_len
+.It Ic ia_pd Op Ar iaid Oo / Ar prefix / Ar prefix_len Oc Op Ar interface Op / Ar sla_id Op / Ar prefix_len
 Request a DHCPv6 Delegated Prefix for
 .Ar iaid .
 This option must be used in an
index 7dd2c9b0048278c0a8db892cc77f66261ea3699d..dec0f46dfa6f0715e198a49d263a37b1554bda34 100644 (file)
@@ -1236,6 +1236,9 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
                fp = strwhite(arg);
                if (fp)
                        *fp++ = '\0';
+               p = strchr(arg, '/');
+               if (p)
+                       *p++ = '\0';
                if (parse_iaid(iaid, arg, sizeof(iaid)) == -1)
                        return -1;
                ia = NULL;
@@ -1262,8 +1265,33 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo,
                        ia->iaid[1] = iaid[1];
                        ia->iaid[2] = iaid[2];
                        ia->iaid[3] = iaid[3];
-                       ia->sla = NULL;
+                       if (p == NULL) {
+                               memset(&ia->addr, 0, sizeof(ia->addr));
+                               ia->prefix_len = 0;
+                       } else {
+                               arg = p;
+                               p = strchr(arg, '/');
+                               if (p)
+                                       *p++ = '\0';
+                               if (inet_pton(AF_INET6, arg, &ia->addr) == -1) {
+                                       syslog(LOG_ERR, "%s: %m", arg);
+                                       memset(&ia->addr, 0, sizeof(ia->addr));
+                               }
+                               if (p) {
+                                       i = atoint(p);
+                                       if (i != -1 && (i < 8 || i > 120)) {
+                                               errno = EINVAL;
+                                               i = -1;
+                                       }
+                                       if (i == -1) {
+                                               syslog(LOG_ERR, "%s: %m", p);
+                                               ia->prefix_len = 0;
+                                       } else
+                                               ia->prefix_len = (uint8_t)i;
+                               }
+                       }
                        ia->sla_len = 0;
+                       ia->sla = NULL;
                }
                if (ifo->ia_type != D6_OPTION_IA_PD)
                        break;
index f90e428e9f6b6b07150c9b3c316a9c57659ae324..bfcca81780e9adbf98717ee3ce60cbe6d967cc0a 100644 (file)
@@ -115,6 +115,8 @@ struct if_sla {
 struct if_ia {
        uint8_t iaid[4];
 #ifdef INET6
+       struct in6_addr addr;
+       uint8_t prefix_len;
        size_t sla_len;
        struct if_sla *sla;
 #endif
diff --git a/ipv6.h b/ipv6.h
index 0b860e2fec7b61867463b5f46dbcb93ce56e5f0b..a12594137c0ef75a1a2c7f7f0b2c1c2fccd484f1 100644 (file)
--- a/ipv6.h
+++ b/ipv6.h
@@ -109,7 +109,8 @@ TAILQ_HEAD(ipv6_addrhead, ipv6_addr);
 #define IPV6_AF_DADCOMPLETED   0x0040
 #define IPV6_AF_DELEGATED      0x0080
 #define IPV6_AF_DELEGATEDPFX   0x0100
-#define IPV6_AF_DELEGATEDZERO  0X0200
+#define IPV6_AF_DELEGATEDZERO  0x0200
+#define IPV6_AF_REQUEST                0x0400
 
 struct rt6 {
        TAILQ_ENTRY(rt6) next;