]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Allow IAID to be configured in DHCPv4 clientid.
authorRoy Marples <roy@marples.name>
Fri, 15 Nov 2013 13:43:41 +0000 (13:43 +0000)
committerRoy Marples <roy@marples.name>
Fri, 15 Nov 2013 13:43:41 +0000 (13:43 +0000)
Use this as the default for DHCPv6 IA's as well.
Rename if_iaid to if_ia as it's really an IA containing an IAID.

dhcp.c
dhcp6.c
dhcpcd.8.in
dhcpcd.c
dhcpcd.conf.5.in
dhcpcd.h
duid.c
duid.h
if-options.c
if-options.h

diff --git a/dhcp.c b/dhcp.c
index c46a7f8c4486b7ad699f2c56903ed3991a714bca..b237ca98c17092251f233ff814c9dd598f19c906 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -2512,8 +2512,7 @@ dhcp_init(struct interface *ifp)
 {
        struct dhcp_state *state;
        const struct if_options *ifo;
-       unsigned char *duid;
-       size_t len, ifl;
+       size_t len;
 
        state = D_STATE(ifp);
        if (state == NULL) {
@@ -2546,33 +2545,15 @@ dhcp_init(struct interface *ifp)
                        goto eexit;
                memcpy(state->clientid, ifo->clientid, ifo->clientid[0] + 1);
        } else if (ifo->options & DHCPCD_CLIENTID) {
-               len = 0;
                if (ifo->options & DHCPCD_DUID) {
-                       duid = malloc(DUID_LEN);
-                       if (duid == NULL)
-                               goto eexit;
-                       if ((len = get_duid(duid, ifp)) == 0)
-                               syslog(LOG_ERR, "get_duid: %m");
-               } else
-                       duid = NULL;
-               if (len > 0) {
-                       state->clientid = malloc(len + 6);
+                       state->clientid = malloc(duid_len + 6);
                        if (state->clientid == NULL)
                                goto eexit;
-                       state->clientid[0] = len + 5;
+                       state->clientid[0] = duid_len + 5;
                        state->clientid[1] = 255; /* RFC 4361 */
-                       ifl = strlen(ifp->name);
-                       if (ifl < 5) {
-                               memcpy(state->clientid + 2, ifp->name, ifl);
-                               if (ifl < 4)
-                                       memset(state->clientid + 2 + ifl,
-                                           0, 4 - ifl);
-                       } else {
-                               ifl = htonl(ifp->index);
-                               memcpy(state->clientid + 2, &ifl, 4);
-                       }
-                       memcpy(state->clientid + 6, duid, len);
-               } else if (len == 0) {
+                       memcpy(state->clientid + 2, ifo->iaid, 4);
+                       memcpy(state->clientid + 6, duid, duid_len);
+               } else {
                        len = ifp->hwlen + 1;
                        state->clientid = malloc(len + 1);
                        if (state->clientid == NULL)
@@ -2582,7 +2563,6 @@ dhcp_init(struct interface *ifp)
                        memcpy(state->clientid + 2, ifp->hwaddr,
                            ifp->hwlen);
                }
-               free(duid);
        }
        if (ifo->options & DHCPCD_CLIENTID)
                syslog(LOG_DEBUG, "%s: using ClientID %s", ifp->name,
diff --git a/dhcp6.c b/dhcp6.c
index a562b73495ad1157de4f87883205bd9ea310674d..fbdc8a461546dd93364c96c163e6cacfb9f9673e 100644 (file)
--- a/dhcp6.c
+++ b/dhcp6.c
@@ -78,8 +78,6 @@ static struct msghdr rcvhdr;
 static struct iovec rcviov[2];
 static unsigned char *rcvbuf;
 static unsigned char ansbuf[1500];
-static unsigned char *duid;
-static uint16_t duid_len;
 static char ntopbuf[INET6_ADDRSTRLEN];
 static char *status;
 static size_t status_len;
@@ -153,7 +151,6 @@ dhcp6_cleanup(void)
 
        free(sndbuf);
        free(rcvbuf);
-       free(duid);
        free(status);
 }
 #endif
@@ -470,7 +467,7 @@ dhcp6_makemessage(struct interface *ifp)
                /* FALLTHROUGH */
        case DH6S_INIT: /* FALLTHROUGH */
        case DH6S_DISCOVER:
-               len += ifo->iaid_len * (sizeof(*o) + (sizeof(u32) * 3));
+               len += ifo->ia_len * (sizeof(*o) + (sizeof(u32) * 3));
                IA = 1;
                break;
        default:
@@ -567,18 +564,18 @@ dhcp6_makemessage(struct interface *ifp)
                o->len = 0;
        }
 
-       for (l = 0; IA && l < ifo->iaid_len; l++) {
+       for (l = 0; IA && l < ifo->ia_len; l++) {
                o = D6_NEXT_OPTION(o);
                o->code = htons(ifo->ia_type);
                o->len = htons(sizeof(u32) + sizeof(u32) + sizeof(u32));
                p = D6_OPTION_DATA(o);
-               memcpy(p, ifo->iaid[l].iaid, sizeof(u32));
+               memcpy(p, ifo->ia[l].iaid, sizeof(u32));
                p += sizeof(u32);
                memset(p, 0, sizeof(u32) + sizeof(u32));
                TAILQ_FOREACH(ap, &state->addrs, next) {
                        if (ap->prefix_vltime == 0)
                                continue;
-                       if (memcmp(ifo->iaid[l].iaid, ap->iaid, sizeof(u32)))
+                       if (memcmp(ifo->ia[l].iaid, ap->iaid, sizeof(u32)))
                                continue;
                        so = D6_NEXT_OPTION(o);
                        if (ifo->ia_type == D6_OPTION_IA_PD) {
@@ -1813,7 +1810,7 @@ dhcp6_delegate_prefix(struct interface *ifp)
        struct dhcp6_state *state, *ifd_state;
        struct ipv6_addr *ap;
        size_t i, j, k;
-       struct if_iaid *iaid;
+       struct if_ia *ia;
        struct if_sla *sla;
        struct interface *ifd;
        uint8_t carrier_warned;
@@ -1829,12 +1826,12 @@ dhcp6_delegate_prefix(struct interface *ifp)
                                syslog(LOG_DEBUG, "%s: delegated prefix %s",
                                    ifp->name, ap->saddr);
                        }
-                       for (i = 0; i < ifo->iaid_len; i++) {
-                               iaid = &ifo->iaid[i];
-                               if (memcmp(iaid->iaid, ap->iaid,
-                                   sizeof(iaid->iaid)))
+                       for (i = 0; i < ifo->ia_len; i++) {
+                               ia = &ifo->ia[i];
+                               if (memcmp(ia->iaid, ap->iaid,
+                                   sizeof(ia->iaid)))
                                        continue;
-                               if (iaid->sla_len == 0) {
+                               if (ia->sla_len == 0) {
                                        /* no SLA configured, so lets
                                         * automate it */
                                        if (ifp == ifd)
@@ -1851,8 +1848,8 @@ dhcp6_delegate_prefix(struct interface *ifp)
                                            NULL, ifp))
                                                k++;
                                }
-                               for (j = 0; j < iaid->sla_len; j++) {
-                                       sla = &iaid->sla[j];
+                               for (j = 0; j < ia->sla_len; j++) {
+                                       sla = &ia->sla[j];
                                        if (strcmp(ifd->name, sla->ifname))
                                                continue;
                                        if (ifd->carrier == LINK_DOWN) {
@@ -1880,12 +1877,12 @@ dhcp6_delegate_prefix(struct interface *ifp)
        }
 
        /* Warn about configured interfaces for delegation that do not exist */
-       for (i = 0; i < ifo->iaid_len; i++) {
-               iaid = &ifo->iaid[i];
-               for (j = 0; j < iaid->sla_len; j++) {
-                       sla = &iaid->sla[j];
+       for (i = 0; i < ifo->ia_len; i++) {
+               ia = &ifo->ia[i];
+               for (j = 0; j < ia->sla_len; j++) {
+                       sla = &ia->sla[j];
                        for (k = 0; k < i; j++)
-                               if (strcmp(sla->ifname, iaid->sla[j].ifname) == 0)
+                               if (strcmp(sla->ifname, ia->sla[j].ifname) == 0)
                                        break;
                        if (j >= i && find_interface(sla->ifname) == NULL)
                                syslog(LOG_ERR,
@@ -1910,7 +1907,7 @@ dhcp6_find_delegates(struct interface *ifp)
        struct dhcp6_state *state;
        struct ipv6_addr *ap;
        size_t i, j, k;
-       struct if_iaid *iaid;
+       struct if_ia *ia;
        struct if_sla *sla;
        struct interface *ifd;
 
@@ -1923,13 +1920,13 @@ dhcp6_find_delegates(struct interface *ifp)
                if (state == NULL || state->state != DH6S_BOUND)
                        continue;
                TAILQ_FOREACH(ap, &state->addrs, next) {
-                       for (i = 0; i < ifo->iaid_len; i++) {
-                               iaid = &ifo->iaid[i];
-                               if (memcmp(iaid->iaid, ap->iaid,
-                                   sizeof(iaid->iaid)))
+                       for (i = 0; i < ifo->ia_len; i++) {
+                               ia = &ifo->ia[i];
+                               if (memcmp(ia->iaid, ap->iaid,
+                                   sizeof(ia->iaid)))
                                        continue;
-                               for (j = 0; j < iaid->sla_len; j++) {
-                                       sla = &iaid->sla[j];
+                               for (j = 0; j < ia->sla_len; j++) {
+                                       sla = &ia->sla[j];
                                        if (strcmp(ifp->name, sla->ifname))
                                                continue;
                                        if (ipv6_linklocal(ifp) == NULL) {
@@ -2417,13 +2414,6 @@ dhcp6_start(struct interface *ifp, enum DH6S init_state)
        if (sock == -1 && dhcp6_open() == -1)
                return -1;
 
-       if (duid == NULL) {
-               duid = malloc(DUID_LEN);
-               if (duid == NULL)
-                       return -1;
-               duid_len = get_duid(duid, ifp);
-       }
-
        ifp->if_data[IF_DATA_DHCP6] = calloc(1, sizeof(*state));
        state = D6_STATE(ifp);
        if (state == NULL)
index c9845470410c87e827a896efcf50659ea6439150..3117c946a8ce758cc58aa75d183c2644e79d7e6a 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd November 12, 2013
+.Dd November 15, 2013
 .Dt DHCPCD 8
 .Os
 .Sh NAME
@@ -125,6 +125,8 @@ is also an implemenation of the DHCPv6 client as specified in
 By default,
 .Nm
 only starts DHCPv6 when instructed to do so by an IPV6 Router Advertisement.
+If no Identity Association is configured,
+then a Non-temporary Address is requested.
 .Ss Local Link configuration
 If
 .Nm
index 36d73824cf72a6eeb56129dee48f63bdd810c909..a01a0b4368f4e33ea5253cf0cec910950f5b8d84 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -57,6 +57,7 @@ const char copyright[] = "Copyright (c) 2006-2013 Roy Marples";
 #include "dev.h"
 #include "dhcpcd.h"
 #include "dhcp6.h"
+#include "duid.h"
 #include "eloop.h"
 #include "if-options.h"
 #include "if-pref.h"
@@ -141,6 +142,7 @@ cleanup(void)
        struct interface *ifp;
        int i;
 
+       free(duid);
        free_options(if_options);
 
        if (ifaces) {
@@ -319,7 +321,7 @@ configure_interface1(struct interface *ifp)
 {
        struct if_options *ifo = ifp->options;
        int ra_global, ra_iface;
-
+       uint32_t len;
        /* Do any platform specific configuration */
        if_conf(ifp);
 
@@ -336,6 +338,9 @@ configure_interface1(struct interface *ifp)
        if (ifo->metric != -1)
                ifp->metric = ifo->metric;
 
+       if (!(ifo->options & DHCPCD_IPV6))
+               ifo->options &= ~DHCPCD_IPV6RS;
+
        /* We want to disable kernel interface RA as early as possible. */
        if (ifo->options & DHCPCD_IPV6RS) {
                ra_global = check_ipv6(NULL, options & DHCPCD_IPV6RA_OWN ? 1:0);
@@ -361,6 +366,35 @@ configure_interface1(struct interface *ifp)
                ifo->options |= DHCPCD_CLIENTID | DHCPCD_BROADCAST;
                break;
        }
+
+       if (!(ifo->options & DHCPCD_IAID)) {
+               len = strlen(ifp->name);
+               if (len <= sizeof(ifo->iaid)) {
+                       memcpy(ifo->iaid, ifp->name, len);
+                       memset(ifo->iaid + len, 0, sizeof(ifo->iaid) - len);
+               } else {
+                       /* IAID is the same size as a uint32_t */
+                       len = htonl(ifp->index);
+                       memcpy(ifo->iaid, &len, sizeof(len));
+               }
+               ifo->options |= DHCPCD_IAID;
+       }
+
+#ifdef INET6
+       if (ifo->ia == NULL && ifo->options & DHCPCD_IPV6) {
+               ifo->ia = malloc(sizeof(*ifo->ia));
+               if (ifo->ia == NULL)
+                       syslog(LOG_ERR, "%s: %m", __func__);
+               else {
+                       if (ifo->ia_type == 0)
+                               ifo->ia_type = D6_OPTION_IA_NA;
+                       memcpy(ifo->ia->iaid, ifo->iaid, sizeof(ifo->iaid));
+                       ifo->ia_len = 1;
+                       ifo->ia->sla = NULL;
+                       ifo->ia->sla_len = 0;
+               }
+       }
+#endif
 }
 
 int
@@ -457,6 +491,7 @@ start_interface(void *arg)
        struct interface *ifp = arg;
        struct if_options *ifo = ifp->options;
        int nolease;
+       size_t i;
 
        handle_carrier(LINK_UNKNOWN, 0, ifp->name);
        if (ifp->carrier == LINK_DOWN) {
@@ -464,6 +499,27 @@ start_interface(void *arg)
                return;
        }
 
+       if (ifo->options & (DHCPCD_DUID | DHCPCD_IPV6)) {
+               /* Report client DUID */
+               if (duid == NULL) {
+                       if (duid_init(ifp) == 0)
+                               return;
+                       syslog(LOG_INFO, "DUID %s",
+                           hwaddr_ntoa(duid, duid_len));
+               }
+
+               /* Report IAIDs */
+               syslog(LOG_INFO, "%s: IAID %s", ifp->name,
+                   hwaddr_ntoa(ifo->iaid, sizeof(ifo->iaid)));
+               for (i = 0; i < ifo->ia_len; i++) {
+                       if (memcmp(ifo->iaid, ifo->ia[i].iaid,
+                           sizeof(ifo->iaid)))
+                               syslog(LOG_INFO, "%s: IAID %s", ifp->name,
+                                   hwaddr_ntoa(ifo->ia[i].iaid,
+                                   sizeof(ifo->ia[i].iaid)));
+               }
+       }
+
        if (ifo->options & DHCPCD_IPV6) {
                if (ifo->options & DHCPCD_IPV6RS &&
                    !(ifo->options & DHCPCD_INFORM))
index c58be91e97369eec9c2cd3bc848aded78b08c00a..535f088adb590b8a7ad6525fc7fb21ac7f376f02 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd October 10, 2013
+.Dd November 15, 2013
 .Dt DHCPCD.CONF 5
 .Os
 .Sh NAME
@@ -135,12 +135,19 @@ Generate an
 .Rs
 .%T "RFC 4361"
 .Re
-compliant clientid.
+compliant DHCP Unique Identifier.
 If persistent storage is available then a DUID-LLT (link local address + time)
 is generated, otherwise DUID-LL is generated (link local address).
+This, plus the IAID will be used as the
+.Ic clientid .
 The DUID-LLT generated will be held in
 .Pa @SYSCONFDIR@/dhcpcd.duid
 and should not be copied to other hosts.
+.It Ic iaid Ar iaid
+Set the Interface Association Identifier to
+.Ar iaid .
+This defaults to the interface name if 4 or less characters.
+If more then it defaults to the interface index.
 .It Ic persistent
 .Nm dhcpcd
 normally de-configures the interface and configuration when it exits.
@@ -172,16 +179,19 @@ option above to control how the hostname is set on the host.
 .It Ic ia_na Op Ar iaid
 Request a DHCPv6 Normal Address for
 .Ar iaid .
-If none is specified, a default
 .Ar iaid
-is used.
-If the interface name is 4 characters or less then that is used,
-otherwise the interface index is used.
-You can request more than one ia_na by specifying a unique iaid for each one.
+defaults to the
+.Ic iaid
+option as described above.
+You can request more than one ia_na by specifying a unique
+.Ar iaid
+for each one.
 .It Ic ia_ta Op Ar iaid
 Request a DHCPv6 Temporary Address for
 .Ar iaid .
-You can request more than one ia_ta by specifying a unique iaid for each one.
+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
 Request a DHCPv6 Delegated Prefix for
 .Ar iaid .
@@ -461,5 +471,7 @@ of a randomly generated number.
 .Sh AUTHORS
 .An Roy Marples Aq Mt roy@marples.name
 .Sh BUGS
+When configuring DHCPv6 you can only select one IA type.
+.Pp
 Please report them to
 .Lk http://roy.marples.name/projects/dhcpcd
index 4f0f56f5e802a66f0bd20c7aeffa4087abeeb235..67fe6d1c11497de722b6c9aec8e3e468b8c0c1ac 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -44,7 +44,7 @@
 #define LINK_DOWN      -1
 
 #define IF_DATA_IPV4   0
-#define IF_DATA_DHCP   1       
+#define IF_DATA_DHCP   1
 #define IF_DATA_IPV6   2
 #define IF_DATA_IPV6ND 3
 #define IF_DATA_DHCP6  4
diff --git a/duid.c b/duid.c
index 4a77f76f6ae2a17070504ddf08c0a8236b0c7180..a119828f3a3d28bcb885fac27cc203d9dc32cbbc 100644 (file)
--- a/duid.c
+++ b/duid.c
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
 #include "duid.h"
 #include "net.h"
 
+unsigned char *duid = NULL;
+size_t duid_len = 0;
+
 static size_t
-make_duid(unsigned char *duid, const struct interface *ifp, uint16_t type)
+duid_make(unsigned char *d, const struct interface *ifp, uint16_t type)
 {
        unsigned char *p;
        uint16_t u16;
        time_t t;
        uint32_t u32;
 
-       p = duid;
+       p = d;
        u16 = htons(type);
        memcpy(p, &u16, 2);
        p += 2;
@@ -77,17 +80,17 @@ make_duid(unsigned char *duid, const struct interface *ifp, uint16_t type)
        /* Finally, add the MAC address of the interface */
        memcpy(p, ifp->hwaddr, ifp->hwlen);
        p += ifp->hwlen;
-       return p - duid;
+       return p - d;
 }
 
-size_t
-get_duid(unsigned char *duid, const struct interface *iface)
+static size_t
+duid_get(unsigned char *d, const struct interface *ifp)
 {
        FILE *f;
        int x = 0;
        size_t len = 0;
        char *line;
-       const struct interface *ifp;
+       const struct interface *ifp2;
 
        /* If we already have a DUID then use it as it's never supposed
         * to change once we have one even if the interfaces do */
@@ -95,7 +98,7 @@ get_duid(unsigned char *duid, const struct interface *iface)
                while ((line = get_line(f))) {
                        len = hwaddr_aton(NULL, line);
                        if (len && len <= DUID_LEN) {
-                               hwaddr_aton(duid, line);
+                               hwaddr_aton(d, line);
                                break;
                        }
                        len = 0;
@@ -109,37 +112,51 @@ get_duid(unsigned char *duid, const struct interface *iface)
        }
 
        /* No file? OK, lets make one based on our interface */
-       if (iface->family == ARPHRD_NETROM) {
+       if (ifp->family == ARPHRD_NETROM) {
                syslog(LOG_WARNING, "%s: is a NET/ROM psuedo interface",
-                   iface->name);
-               TAILQ_FOREACH(ifp, ifaces, next) {
-                       if (ifp->family != ARPHRD_NETROM)
+                   ifp->name);
+               TAILQ_FOREACH(ifp2, ifaces, next) {
+                       if (ifp2->family != ARPHRD_NETROM)
                                break;
                }
-               if (ifp) {
-                       iface = ifp;
+               if (ifp2) {
+                       ifp = ifp2;
                        syslog(LOG_WARNING,
                            "picked interface %s to generate a DUID",
-                           iface->name);
+                           ifp->name);
                } else {
                        syslog(LOG_WARNING,
                            "no interfaces have a fixed hardware address");
-                       return make_duid(duid, iface, DUID_LL);
+                       return duid_make(d, ifp, DUID_LL);
                }
        }
 
        if (!(f = fopen(DUID, "w"))) {
                syslog(LOG_ERR, "error writing DUID: %s: %m", DUID);
-               return make_duid(duid, iface, DUID_LL);
+               return duid_make(d, ifp, DUID_LL);
        }
-       len = make_duid(duid, iface, DUID_LLT);
-       x = fprintf(f, "%s\n", hwaddr_ntoa(duid, len));
+       len = duid_make(d, ifp, DUID_LLT);
+       x = fprintf(f, "%s\n", hwaddr_ntoa(d, len));
        fclose(f);
        /* Failed to write the duid? scrub it, we cannot use it */
        if (x < 1) {
                syslog(LOG_ERR, "error writing DUID: %s: %m", DUID);
                unlink(DUID);
-               return make_duid(duid, iface, DUID_LL);
+               return duid_make(d, ifp, DUID_LL);
        }
        return len;
 }
+
+size_t duid_init(const struct interface *ifp)
+{
+
+       if (duid == NULL) {
+               duid = malloc(DUID_LEN);
+               if (duid == NULL) {
+                       syslog(LOG_ERR, "%s: %m", __func__);
+                       return 0;
+               }
+               duid_len = duid_get(duid, ifp);
+       }
+       return duid_len;
+}
diff --git a/duid.h b/duid.h
index 4693102bff3977b9ef476191794dd3db5c8deecb..b3ab00ee65bab54e5f261c8a5b6a717009f3d320 100644 (file)
--- a/duid.h
+++ b/duid.h
@@ -1,6 +1,6 @@
 /*
  * dhcpcd - DHCP client daemon
- * Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
+ * Copyright (c) 2006-2013 Roy Marples <roy@marples.name>
  * All rights reserved
 
  * Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,9 @@
 
 #include "net.h"
 
-size_t get_duid(unsigned char *duid, const struct interface *iface);
+extern unsigned char *duid;
+extern size_t duid_len;
+
+size_t duid_init(const struct interface *);
 
 #endif
index f0a09e33ee404163ff156c0a08ab8e45488daf76..effc6e54fa4088d5ba9eb845d6f5917b76db8795 100644 (file)
@@ -72,6 +72,7 @@ unsigned long long options = 0;
 #define O_NODEV                        O_BASE + 15
 #define O_NOIPV4               O_BASE + 16
 #define O_NOIPV6               O_BASE + 17
+#define O_IAID                 O_BASE + 18
 
 char *dev_load;
 
@@ -134,6 +135,7 @@ const struct option cf_options[] = {
        {"noipv4",          no_argument,       NULL, O_NOIPV4},
        {"noipv6",          no_argument,       NULL, O_NOIPV6},
        {"noalias",         no_argument,       NULL, O_NOALIAS},
+       {"iaid",            no_argument,       NULL, O_IAID},
        {"ia_na",           no_argument,       NULL, O_IA_NA},
        {"ia_ta",           no_argument,       NULL, O_IA_TA},
        {"ia_pd",           no_argument,       NULL, O_IA_PD},
@@ -334,6 +336,35 @@ parse_string_hwaddr(char *sbuf, ssize_t slen, const char *str, int clid)
        return l;
 }
 
+static int
+parse_iaid(uint8_t *iaid, const char *arg, size_t len)
+{
+       unsigned long l;
+       size_t s;
+       uint32_t u32;
+       char *np;
+
+       errno = 0;
+       l = strtoul(arg, &np, 0);
+       if (l <= (unsigned long)UINT32_MAX && errno == 0 && *np == '\0') {
+               u32 = htonl(l);
+               memcpy(iaid, &u32, sizeof(u32));
+               return 0;
+       }
+
+       if ((s = parse_string((char *)iaid, len, arg)) < 1) {
+               syslog(LOG_ERR, "%s: invalid IAID", arg);
+               return -1;
+       }
+       if (s < 4)
+               iaid[3] = '\0';
+       if (s < 3)
+               iaid[2] = '\0';
+       if (s < 2)
+               iaid[1] = '\0';
+       return 0;
+}
+
 static char **
 splitv(int *argc, char **argv, const char *arg)
 {
@@ -449,11 +480,9 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
        const struct dhcp_opt *d;
        uint8_t *request, *require, *no;
 #ifdef INET6
-       long l;
-       uint32_t u32;
        size_t sl;
-       struct if_iaid *iaid;
-       uint8_t _iaid[4];
+       struct if_ia *ia;
+       uint8_t iaid[4];
        struct if_sla *sla, *slap;
 #endif
 
@@ -520,7 +549,7 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
                        return -1;
                }
                errno = 0;
-               ifo->leasetime = (uint32_t)strtol(arg, NULL, 0);
+               ifo->leasetime = (uint32_t)strtoul(arg, NULL, 0);
                if (errno == EINVAL || errno == ERANGE) {
                        syslog(LOG_ERR, "`%s' out of range", arg);
                        return -1;
@@ -954,6 +983,10 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
                }
                break;
 #endif
+       case O_IAID:
+               if (parse_iaid(ifo->iaid, arg, sizeof(ifo->iaid)) == -1)
+                       return -1;
+               ifo->options |= DHCPCD_IAID;
        case O_IPV6RS:
                ifo->options |= DHCPCD_IPV6RS;
                break;
@@ -994,52 +1027,34 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
                fp = strchr(arg, ' ');
                if (fp)
                        *fp++ = '\0';
-               errno = 0;
-               l = strtol(arg, &np, 0);
-               if (l >= 0 && l <= (long)UINT32_MAX &&
-                   errno == 0 && *np == '\0')
-               {
-                       u32 = htonl(l);
-                       memcpy(&_iaid, &u32, sizeof(_iaid));
-                       goto got_iaid;
-               }
-               if ((s = parse_string((char *)_iaid, sizeof(_iaid), arg)) < 1) {
-                       syslog(LOG_ERR, "%s: invalid IAID", arg);
+               if (parse_iaid(iaid, arg, sizeof(iaid)) == -1)
                        return -1;
-               }
-               if (s < 4)
-                       _iaid[3] = '\0';
-               if (s < 3)
-                       _iaid[2] = '\0';
-               if (s < 2)
-                       _iaid[1] = '\0';
-got_iaid:
-               iaid = NULL;
-               for (sl = 0; sl < ifo->iaid_len; sl++) {
-                       if (ifo->iaid[sl].iaid[0] == _iaid[0] &&
-                           ifo->iaid[sl].iaid[1] == _iaid[1] &&
-                           ifo->iaid[sl].iaid[2] == _iaid[2] &&
-                           ifo->iaid[sl].iaid[3] == _iaid[3])
+               ia = NULL;
+               for (sl = 0; sl < ifo->ia_len; sl++) {
+                       if (ifo->ia[sl].iaid[0] == iaid[0] &&
+                           ifo->ia[sl].iaid[1] == iaid[1] &&
+                           ifo->ia[sl].iaid[2] == iaid[2] &&
+                           ifo->ia[sl].iaid[3] == iaid[3])
                        {
-                               iaid = &ifo->iaid[sl];
+                               ia = &ifo->ia[sl];
                                break;
                        }
                }
-               if (iaid == NULL) {
-                       iaid = realloc(ifo->iaid,
-                           sizeof(*ifo->iaid) * (ifo->iaid_len + 1));
-                       if (iaid == NULL) {
+               if (ia == NULL) {
+                       ia = realloc(ifo->ia,
+                           sizeof(*ifo->ia) * (ifo->ia_len + 1));
+                       if (ia == NULL) {
                                syslog(LOG_ERR, "%s: %m", __func__);
                                return -1;
                        }
-                       ifo->iaid = iaid;
-                       iaid = &ifo->iaid[ifo->iaid_len++];
-                       iaid->iaid[0] = _iaid[0];
-                       iaid->iaid[1] = _iaid[1];
-                       iaid->iaid[2] = _iaid[2];
-                       iaid->iaid[3] = _iaid[3];
-                       iaid->sla = NULL;
-                       iaid->sla_len = 0;
+                       ifo->ia = ia;
+                       ia = &ifo->ia[ifo->ia_len++];
+                       ia->iaid[0] = iaid[0];
+                       ia->iaid[1] = iaid[1];
+                       ia->iaid[2] = iaid[2];
+                       ia->iaid[3] = iaid[3];
+                       ia->sla = NULL;
+                       ia->sla_len = 0;
                }
                if (ifo->ia_type != D6_OPTION_IA_PD)
                        break;
@@ -1047,14 +1062,14 @@ got_iaid:
                        fp = strchr(p, ' ');
                        if (fp)
                                *fp++ = '\0';
-                       sla = realloc(iaid->sla,
-                           sizeof(*iaid->sla) * (iaid->sla_len + 1));
+                       sla = realloc(ia->sla,
+                           sizeof(*ia->sla) * (ia->sla_len + 1));
                        if (sla == NULL) {
                                syslog(LOG_ERR, "%s: %m", __func__);
                                return -1;
                        }
-                       iaid->sla = sla;
-                       sla = &iaid->sla[iaid->sla_len++];
+                       ia->sla = sla;
+                       sla = &ia->sla[ia->sla_len++];
                        np = strchr(p, '/');
                        if (np)
                                *np++ = '\0';
@@ -1090,8 +1105,8 @@ got_iaid:
                                sla->sla_set = 0;
                                /* Sanity - check there are no more
                                 * unspecified SLA's */
-                               for (sl = 0; sl < iaid->sla_len - 1; sl++) {
-                                       slap = &iaid->sla[sl];
+                               for (sl = 0; sl < ia->sla_len - 1; sl++) {
+                                       slap = &ia->sla[sl];
                                        if (slap->sla_set == 0 &&
                                            strcmp(slap->ifname, sla->ifname)
                                            == 0)
@@ -1101,14 +1116,14 @@ got_iaid:
                                                    "same interface twice with "
                                                    "an automatic SLA",
                                                    sla->ifname);
-                                               iaid->sla_len--;
+                                               ia->sla_len--;
                                                break;
                                        }
                                }
                        }
                }
-               break;
 #endif
+               break;
        case O_HOSTNAME_SHORT:
                ifo->options |= DHCPCD_HOSTNAME | DHCPCD_HOSTNAME_SHORT;
                break;
@@ -1166,39 +1181,6 @@ finish_config(struct if_options *ifo)
        }
 }
 
-#ifdef INET6
-static void
-finish_config6(struct if_options *ifo, const char *ifname)
-{
-
-       if (!(ifo->options & DHCPCD_IPV6))
-               ifo->options &= ~DHCPCD_IPV6RS;
-
-       if (ifname && ifo->iaid_len == 0 && ifo->options & DHCPCD_IPV6) {
-               ifo->iaid = malloc(sizeof(*ifo->iaid));
-               if (ifo->iaid == NULL)
-                       syslog(LOG_ERR, "%s: %m", __func__);
-               else {
-                       if (ifo->ia_type == 0)
-                               ifo->ia_type = D6_OPTION_IA_NA;
-                       ifo->iaid_len = strlen(ifname);
-                       if (ifo->iaid_len <= sizeof(ifo->iaid->iaid)) {
-                               strncpy((char *)ifo->iaid->iaid, ifname,
-                                       sizeof(ifo->iaid->iaid));
-                               memset(ifo->iaid->iaid + ifo->iaid_len, 0,
-                                       sizeof(ifo->iaid->iaid) -ifo->iaid_len);
-                       } else {
-                               uint32_t idx = if_nametoindex(ifname);
-                               memcpy(ifo->iaid->iaid, &idx, sizeof(idx));
-                       }
-                       ifo->iaid_len = 1;
-                       ifo->iaid->sla = NULL;
-                       ifo->iaid->sla_len = 0;
-               }
-       }
-}
-#endif
-
 struct if_options *
 read_config(const char *file,
     const char *ifname, const char *ssid, const char *profile)
@@ -1290,9 +1272,6 @@ read_config(const char *file,
        }
 
        finish_config(ifo);
-#ifdef INET6
-       finish_config6(ifo, ifname);
-#endif
        return ifo;
 }
 
@@ -1314,9 +1293,6 @@ add_options(struct if_options *ifo, int argc, char **argv)
        }
 
        finish_config(ifo);
-#ifdef INET6
-       finish_config6(ifo, NULL);
-#endif
        return r;
 }
 
@@ -1343,10 +1319,11 @@ free_options(struct if_options *ifo)
                free(ifo->blacklist);
                free(ifo->fallback);
 #ifdef INET6
-               for (i = 0; i < ifo->iaid_len; i++)
-                       free(ifo->iaid[i].sla);
-               free(ifo->iaid);
+               for (i = 0; i < ifo->ia_len; i++)
+                       free(ifo->ia[i].sla);
 #endif
+               free(ifo->ia);
+
                free(ifo);
        }
 }
index 80bb59021946374d7ec9571056ebf1c8ba4bcb20..e3189ad40b375d4095a1028e560f011242ba874c 100644 (file)
@@ -97,6 +97,7 @@
 #define DHCPCD_WAITIP4                 (1ULL << 45)
 #define DHCPCD_WAITIP6                 (1ULL << 46)
 #define DHCPCD_DEV                     (1ULL << 47)
+#define DHCPCD_IAID                    (1ULL << 48)
 
 extern const struct option cf_options[];
 
@@ -107,13 +108,16 @@ struct if_sla {
        int8_t sla_set;
 };
 
-struct if_iaid {
+struct if_ia {
        uint8_t iaid[4];
+#ifdef INET6
        size_t sla_len;
        struct if_sla *sla;
+#endif
 };
 
 struct if_options {
+       uint8_t iaid[4];
        int metric;
        uint8_t requestmask[256 / 8];
        uint8_t requiremask[256 / 8];
@@ -150,10 +154,10 @@ struct if_options {
        in_addr_t *arping;
        char *fallback;
 
-#ifdef INET6
        uint16_t ia_type;
-       size_t iaid_len;
-       struct if_iaid *iaid;
+       struct if_ia *ia;
+       size_t ia_len;
+#ifdef INET6
        int dadtransmits;
 #endif
 };