[packages/dhcpcd] - correct patch
arekm
arekm at pld-linux.org
Wed Nov 6 14:56:58 CET 2019
commit 4269699a1aad65a58e2fce90ee2e17a9f9cda6cf
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date: Wed Nov 6 14:56:48 2019 +0100
- correct patch
cpuhog.patch | 52 +
dhcpcd-git.patch | 3014 ------------------------------------------------------
2 files changed, 52 insertions(+), 3014 deletions(-)
---
diff --git a/cpuhog.patch b/cpuhog.patch
new file mode 100644
index 0000000..58863ae
--- /dev/null
+++ b/cpuhog.patch
@@ -0,0 +1,52 @@
+From 73ac184333f77b38a8b4c4202c2928278e2237ca Mon Sep 17 00:00:00 2001
+From: Roy Marples <roy at marples.name>
+Date: Tue, 5 Nov 2019 15:52:57 +0000
+Subject: INET: Fix corruption of IPv4 address flags when renewing
+
+What a mistaka to maka!
+---
+ src/ipv4.c | 20 +++++++++-----------
+ 1 file changed, 9 insertions(+), 11 deletions(-)
+
+(limited to 'src')
+
+diff --git a/src/ipv4.c b/src/ipv4.c
+index fd2a15d7..53550696 100644
+--- a/src/ipv4.c
++++ b/src/ipv4.c
+@@ -654,7 +654,7 @@ ipv4_addaddr(struct interface *ifp, const struct in_addr *addr,
+ #endif
+ ia->flags = IPV4_AF_NEW;
+ } else
+- ia->flags |= ~IPV4_AF_NEW;
++ ia->flags &= ~IPV4_AF_NEW;
+
+ ia->mask = *mask;
+ ia->brd = *bcast;
+@@ -952,15 +952,13 @@ ipv4_free(struct interface *ifp)
+ struct ipv4_state *state;
+ struct ipv4_addr *ia;
+
+- if (ifp) {
+- state = IPV4_STATE(ifp);
+- if (state) {
+- while ((ia = TAILQ_FIRST(&state->addrs))) {
+- TAILQ_REMOVE(&state->addrs, ia, next);
+- free(ia);
+- }
+- free(state->buffer);
+- free(state);
+- }
++ if (ifp == NULL || (state = IPV4_STATE(ifp)) == NULL)
++ return;
++
++ while ((ia = TAILQ_FIRST(&state->addrs))) {
++ TAILQ_REMOVE(&state->addrs, ia, next);
++ free(ia);
+ }
++ free(state->buffer);
++ free(state);
+ }
+--
+cgit v1.2.1
+
diff --git a/dhcpcd-git.patch b/dhcpcd-git.patch
deleted file mode 100644
index 9a77b9c..0000000
--- a/dhcpcd-git.patch
+++ /dev/null
@@ -1,3014 +0,0 @@
-diff -urN dhcpcd-6.4.0.org/configure dhcpcd-6.4.0/configure
---- dhcpcd-6.4.0.org/configure 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/configure 2014-07-05 21:47:22.000000000 +0200
-@@ -272,8 +272,18 @@
- fi
-
- echo "Using compiler .. $CC"
--if ! type "$CC" >/dev/null 2>&1; then
-- echo "$CC is not an executable"
-+cat <<EOF >_test.c
-+int main(void) {
-+ return 0;
-+}
-+EOF
-+_CC=false
-+if $CC _test.c -o _test >/dev/null 2>&1; then
-+ [ -x _test ] && _CC=true
-+fi
-+rm -f _test.c _test
-+if ! $_CC; then
-+ echo "$CC does not create executables"
- exit 1
- fi
- [ "$CC" != cc ] && echo "CC= $CC" >>$CONFIG_MK
-@@ -422,7 +432,7 @@
- EOF
- if $XCC _getifaddrs.c -o _getifaddrs 2>/dev/null; then
- echo "yes"
--elif $XCC _getifaddrs.c -o _getifaddrs -lsocket >/dev/null; then
-+elif $XCC _getifaddrs.c -o _getifaddrs -lsocket 2>/dev/null; then
- echo "yes (-lsocket)"
- echo "LDADD+= -lsocket" >>$CONFIG_MK
- else
-diff -urN dhcpcd-6.4.0.org/control.c dhcpcd-6.4.0/control.c
---- dhcpcd-6.4.0.org/control.c 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/control.c 2014-07-05 21:47:22.000000000 +0200
-@@ -52,8 +52,9 @@
- control_handle_data(void *arg)
- {
- struct fd_list *l = arg, *lp, *last;
-- char buffer[1024], *e, *p, *argvp[255], **ap;
-+ char buffer[1024], *e, *p, *argvp[255], **ap, *a;
- ssize_t bytes;
-+ size_t len;
- int argc;
-
- bytes = read(l->fd, buffer, sizeof(buffer) - 1);
-@@ -79,14 +80,28 @@
- buffer[bytes] = '\0';
- p = buffer;
- e = buffer + bytes;
-- argc = 0;
-- ap = argvp;
-- while (p < e && (size_t)argc < sizeof(argvp)) {
-- argc++;
-- *ap++ = p;
-- p += strlen(p) + 1;
-+
-+ /* Each command is \n terminated
-+ * Each argument is NULL separated */
-+ while (p < e) {
-+ argc = 0;
-+ ap = argvp;
-+ while (p < e) {
-+ argc++;
-+ if ((size_t)argc > sizeof(argvp)) {
-+ errno = ENOBUFS;
-+ return;
-+ }
-+ a = *ap++ = p;
-+ len = strlen(p);
-+ p += len + 1;
-+ if (a[len - 1] == '\n') {
-+ a[len - 1] = '\0';
-+ break;
-+ }
-+ }
-+ dhcpcd_handleargs(l->ctx, l, argc, argvp);
- }
-- dhcpcd_handleargs(l->ctx, l, argc, argvp);
- }
-
- static void
-diff -urN dhcpcd-6.4.0.org/defs.h dhcpcd-6.4.0/defs.h
---- dhcpcd-6.4.0.org/defs.h 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/defs.h 2014-07-05 21:47:22.000000000 +0200
-@@ -49,7 +49,7 @@
- # define LEASEFILE DBDIR "/" PACKAGE "-%s.lease"
- #endif
- #ifndef LEASEFILE6
--# define LEASEFILE6 DBDIR "/" PACKAGE "-%s.lease6"
-+# define LEASEFILE6 DBDIR "/" PACKAGE "-%s%s.lease6"
- #endif
- #ifndef PIDFILE
- # define PIDFILE RUNDIR "/" PACKAGE "%s%s%s.pid"
-diff -urN dhcpcd-6.4.0.org/dhcp6.c dhcpcd-6.4.0/dhcp6.c
---- dhcpcd-6.4.0.org/dhcp6.c 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcp6.c 2014-07-05 21:47:22.000000000 +0200
-@@ -121,13 +121,22 @@
- };
-
- void
--dhcp6_printoptions(const struct dhcpcd_ctx *ctx)
-+dhcp6_printoptions(const struct dhcpcd_ctx *ctx,
-+ const struct dhcp_opt *opts, size_t opts_len)
- {
-- size_t i;
-- const struct dhcp_opt *opt;
-+ size_t i, j;
-+ const struct dhcp_opt *opt, *opt2;
-
- for (i = 0, opt = ctx->dhcp6_opts;
- i < ctx->dhcp6_opts_len; i++, opt++)
-+ {
-+ for (j = 0, opt2 = opts; j < opts_len; j++, opt2++)
-+ if (opt2->option == opt->option)
-+ break;
-+ if (j == opts_len)
-+ printf("%05d %s\n", opt->option, opt->var);
-+ }
-+ for (i = 0, opt = opts; i < opts_len; i++, opt++)
- printf("%05d %s\n", opt->option, opt->var);
- }
-
-@@ -304,24 +313,112 @@
- m->xid[2] = xid & 0xff;
- }
-
-+static const struct if_sla *
-+dhcp6_findselfsla(struct interface *ifp, const uint8_t *iaid)
-+{
-+ size_t i, j;
-+
-+ for (i = 0; i < ifp->options->ia_len; i++) {
-+ if (iaid == NULL ||
-+ memcmp(&ifp->options->ia[i].iaid, iaid,
-+ sizeof(ifp->options->ia[i].iaid)) == 0)
-+ {
-+ for (j = 0; j < ifp->options->ia[i].sla_len; j++) {
-+ if (strcmp(ifp->options->ia[i].sla[j].ifname,
-+ ifp->name) == 0)
-+ return &ifp->options->ia[i].sla[j];
-+ }
-+ }
-+ }
-+ return NULL;
-+}
-+
-+static int
-+dhcp6_delegateaddr(struct in6_addr *addr, struct interface *ifp,
-+ const struct ipv6_addr *prefix, const struct if_sla *sla)
-+{
-+ struct dhcp6_state *state;
-+ struct if_sla asla;
-+ char iabuf[INET6_ADDRSTRLEN];
-+ const char *ia;
-+
-+ state = D6_STATE(ifp);
-+ if (state == NULL) {
-+ ifp->if_data[IF_DATA_DHCP6] = calloc(1, sizeof(*state));
-+ state = D6_STATE(ifp);
-+ if (state == NULL) {
-+ syslog(LOG_ERR, "%s: %m", __func__);
-+ return -1;
-+ }
-+
-+ TAILQ_INIT(&state->addrs);
-+ state->state = DH6S_DELEGATED;
-+ state->reason = "DELEGATED6";
-+ }
-+
-+ if (sla == NULL || sla->sla_set == 0) {
-+ struct interface *ifi;
-+ unsigned int idx;
-+ int bits;
-+
-+ asla.sla = ifp->index;
-+ /* Work out our largest index delegating to. */
-+ idx = 0;
-+ TAILQ_FOREACH(ifi, ifp->ctx->ifaces, next) {
-+ if (ifi != ifp && ifi->index > idx)
-+ idx = ifi->index;
-+ }
-+ bits = ffs((int)idx);
-+ if (prefix->prefix_len + bits > UINT8_MAX)
-+ asla.prefix_len = UINT8_MAX;
-+ else {
-+ asla.prefix_len = prefix->prefix_len + (uint8_t)bits;
-+
-+ /* Make a 64 prefix by default, as this maks SLAAC
-+ * possible. Otherwise round up to the nearest octet. */
-+ if (asla.prefix_len <= 64)
-+ asla.prefix_len = 64;
-+ else
-+ asla.prefix_len = ROUNDUP8(asla.prefix_len);
-+
-+ }
-+ sla = &asla;
-+ }
-+
-+ if (ipv6_userprefix(&prefix->prefix, prefix->prefix_len,
-+ sla->sla, addr, sla->prefix_len) == -1)
-+ {
-+ ia = inet_ntop(AF_INET6, &prefix->prefix.s6_addr,
-+ iabuf, sizeof(iabuf));
-+ syslog(LOG_ERR, "%s: invalid prefix %s/%d + %d/%d: %m",
-+ ifp->name, ia, prefix->prefix_len,
-+ sla->sla, sla->prefix_len);
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
- static int
- dhcp6_makemessage(struct interface *ifp)
- {
- struct dhcp6_state *state;
- struct dhcp6_message *m;
-- struct dhcp6_option *o, *so;
-+ struct dhcp6_option *o, *so, *eo;
- const struct dhcp6_option *si, *unicast;
-- size_t l, len, ml, auth_len;
-+ size_t l, n, len, ml, auth_len;
- uint8_t u8, type;
- uint16_t *u16, n_options;
- struct if_options *ifo;
-- const struct dhcp_opt *opt;
-+ const struct dhcp_opt *opt, *opt2;
- uint8_t IA, *p;
- uint32_t u32;
- const struct ipv6_addr *ap;
- char hbuf[HOSTNAME_MAX_LEN + 1];
- const char *hostname;
- int fqdn;
-+ const struct if_sla *sla;
-+ struct in6_addr addr;
-
- state = D6_STATE(ifp);
- if (state->send) {
-@@ -356,6 +453,15 @@
- l < ifp->ctx->dhcp6_opts_len;
- l++, opt++)
- {
-+ for (n = 0, opt2 = ifo->dhcp6_override;
-+ n < ifo->dhcp6_override_len;
-+ n++, opt2++)
-+ {
-+ if (opt->option == opt2->option)
-+ break;
-+ }
-+ if (n < ifo->dhcp6_override_len)
-+ continue;
- if (!(opt->type & NOREQ) &&
- (opt->type & REQUEST ||
- has_option_mask(ifo->requestmask6, opt->option)))
-@@ -364,6 +470,22 @@
- len += sizeof(*u16);
- }
- }
-+ for (l = 0, opt = ifo->dhcp6_override;
-+ l < ifo->dhcp6_override_len;
-+ l++, opt++)
-+ {
-+ if (!(opt->type & NOREQ) &&
-+ (opt->type & REQUEST ||
-+ has_option_mask(ifo->requestmask6, opt->option)))
-+ {
-+ n_options++;
-+ len += sizeof(*u16);
-+ }
-+ }
-+ if (dhcp6_findselfsla(ifp, NULL)) {
-+ n_options++;
-+ len += sizeof(*u16);
-+ }
- if (len)
- len += sizeof(*o);
-
-@@ -405,25 +527,43 @@
- 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) +
-- sizeof(u32) + sizeof(u32) +
-- sizeof(ap->prefix.s6_addr);
-- else
-+ if (ap->ia_type == D6_OPTION_IA_PD) {
-+ if (!(ifo->options & DHCPCD_NOPFXDLG)) {
-+ len += sizeof(*o) + sizeof(u8) +
-+ sizeof(u32) + sizeof(u32) +
-+ sizeof(ap->prefix.s6_addr);
-+ sla = dhcp6_findselfsla(ifp, ap->iaid);
-+ if (sla)
-+ len += sizeof(*o) + 1 +
-+ ((sla->prefix_len -
-+ ap->prefix_len - 1) / NBBY)
-+ + 1;
-+
-+ }
-+ } else if (!(ifo->options & DHCPCD_PFXDLGONLY))
- len += sizeof(*o) + sizeof(ap->addr.s6_addr) +
- sizeof(u32) + sizeof(u32);
- }
- /* FALLTHROUGH */
-- case DH6S_INIT: /* FALLTHROUGH */
-- case DH6S_DISCOVER:
-- len += ifo->ia_len * (sizeof(*o) + (sizeof(u32) * 3));
-+ case DH6S_INIT:
-+ for (l = 0; l < ifo->ia_len; l++) {
-+ if (ifo->ia[l].ia_type == D6_OPTION_IA_PD) {
-+ if (ifo->options & DHCPCD_NOPFXDLG)
-+ continue;
-+ } else if (ifo->options & DHCPCD_PFXDLGONLY)
-+ continue;
-+ len += sizeof(*o) + (sizeof(u32) * 3);
-+ }
- IA = 1;
- break;
- default:
-@@ -528,20 +668,26 @@
- }
-
- for (l = 0; IA && l < ifo->ia_len; l++) {
-+ if (ifo->ia[l].ia_type == D6_OPTION_IA_PD) {
-+ if (ifo->options & DHCPCD_NOPFXDLG)
-+ continue;
-+ } else if (ifo->options & DHCPCD_PFXDLGONLY)
-+ continue;
- o = D6_NEXT_OPTION(o);
-- o->code = htons(ifo->ia_type);
-+ o->code = htons(ifo->ia[l].ia_type);
- o->len = htons(sizeof(u32) + sizeof(u32) + sizeof(u32));
- p = D6_OPTION_DATA(o);
- 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)
-+ if (ap->prefix_vltime == 0 &&
-+ !(ap->flags & IPV6_AF_REQUEST))
- continue;
- if (memcmp(ifo->ia[l].iaid, ap->iaid, sizeof(u32)))
- continue;
- so = D6_NEXT_OPTION(o);
-- if (ifo->ia_type == D6_OPTION_IA_PD) {
-+ if (ap->ia_type == D6_OPTION_IA_PD) {
- so->code = htons(D6_OPTION_IAPREFIX);
- so->len = htons(sizeof(ap->prefix.s6_addr) +
- sizeof(u32) + sizeof(u32) + sizeof(u8));
-@@ -557,16 +703,45 @@
- p += sizeof(u8);
- memcpy(p, &ap->prefix.s6_addr,
- sizeof(ap->prefix.s6_addr));
-- /* Avoid a shadowed declaration warning by
-- * moving our addition outside of the htons
-- * macro */
-+
-+ /* RFC6603 Sectio 4.2 */
-+ sla = dhcp6_findselfsla(ifp, ap->iaid);
-+ if (sla &&
-+ dhcp6_delegateaddr(&addr, ifp, ap, sla) ==0)
-+ {
-+ uint16_t el;
-+ uint8_t *pp;
-+
-+ el = ((sla->prefix_len -
-+ ap->prefix_len - 1) / NBBY) + 1;
-+ eo = D6_NEXT_OPTION(so);
-+ eo->code = htons(D6_OPTION_PD_EXCLUDE);
-+ eo->len = el + 1;
-+ p = D6_OPTION_DATA(eo);
-+ *p++ = (uint8_t)sla->prefix_len;
-+ pp = addr.s6_addr;
-+ pp += (ap->prefix_len - 1) / NBBY;
-+ u8 = ap->prefix_len % NBBY;
-+ if (u8 % NBBY == 0)
-+ pp++;
-+ else {
-+ *p = (uint8_t)(*pp++ << u8);
-+ el--;
-+ }
-+ memcpy(p, pp, el);
-+ u32 = ntohs(so->len) +
-+ sizeof(*eo) + eo->len;
-+ so->len = htons(u32);
-+ eo->len = htons(eo->len);
-+ }
-+
- u32 = ntohs(o->len) + sizeof(*so)
- + ntohs(so->len);
- o->len = htons(u32);
- } else {
- so->code = htons(D6_OPTION_IA_ADDR);
-- so->len = htons(sizeof(ap->addr.s6_addr) +
-- sizeof(u32) + sizeof(u32));
-+ so->len = sizeof(ap->addr.s6_addr) +
-+ sizeof(u32) + sizeof(u32);
- p = D6_OPTION_DATA(so);
- memcpy(p, &ap->addr.s6_addr,
- sizeof(ap->addr.s6_addr));
-@@ -576,11 +751,9 @@
- p += sizeof(u32);
- u32 = htonl(ap->prefix_vltime);
- memcpy(p, &u32, sizeof(u32));
-- /* Avoid a shadowed declaration warning by
-- * moving our addition outside of the htons
-- * macro */
- u32 = ntohs(o->len) + sizeof(*so)
-- + ntohs(so->len);
-+ + so->len;
-+ so->len = htons(so->len);
- o->len = htons(u32);
- }
- }
-@@ -625,6 +798,28 @@
- l < ifp->ctx->dhcp6_opts_len;
- l++, opt++)
- {
-+ for (n = 0, opt2 = ifo->dhcp6_override;
-+ n < ifo->dhcp6_override_len;
-+ n++, opt2++)
-+ {
-+ if (opt->option == opt2->option)
-+ break;
-+ }
-+ if (n < ifo->dhcp6_override_len)
-+ continue;
-+ if (!(opt->type & NOREQ) &&
-+ (opt->type & REQUEST ||
-+ has_option_mask(ifo->requestmask6,
-+ opt->option)))
-+ {
-+ *u16++ = htons(opt->option);
-+ o->len += sizeof(*u16);
-+ }
-+ }
-+ for (l = 0, opt = ifo->dhcp6_override;
-+ l < ifo->dhcp6_override_len;
-+ l++, opt++)
-+ {
- if (!(opt->type & NOREQ) &&
- (opt->type & REQUEST ||
- has_option_mask(ifo->requestmask6,
-@@ -634,6 +829,10 @@
- o->len += sizeof(*u16);
- }
- }
-+ if (dhcp6_findselfsla(ifp, NULL)) {
-+ *u16++ = htons(D6_OPTION_PD_EXCLUDE);
-+ o->len += sizeof(*u16);
-+ }
- o->len = htons(o->len);
- }
- }
-@@ -949,6 +1148,99 @@
- }
-
- 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_addrequestedaddrs(struct interface *ifp)
-+{
-+ struct dhcp6_state *state;
-+ size_t i;
-+ struct if_ia *ia;
-+ struct ipv6_addr *a;
-+ char iabuf[INET6_ADDRSTRLEN];
-+ const char *iap;
-+
-+ state = D6_STATE(ifp);
-+ /* Add any requested prefixes / addresses */
-+ for (i = 0; i < ifp->options->ia_len; i++) {
-+ ia = &ifp->options->ia[i];
-+ if (!((ia->ia_type == D6_OPTION_IA_PD && ia->prefix_len) ||
-+ !IN6_IS_ADDR_UNSPECIFIED(&ia->addr)))
-+ continue;
-+ a = calloc(1, sizeof(*a));
-+ if (a == NULL) {
-+ syslog(LOG_ERR, "%s: %m", __func__);
-+ return;
-+ }
-+ a->flags = IPV6_AF_REQUEST;
-+ a->iface = ifp;
-+ a->dadcallback = dhcp6_dadcallback;
-+ memcpy(&a->iaid, &ia->iaid, sizeof(a->iaid));
-+ a->ia_type = ia->ia_type;
-+ //a->prefix_pltime = 0;
-+ //a->prefix_vltime = 0;
-+
-+ if (ia->ia_type == D6_OPTION_IA_PD) {
-+ memcpy(&a->prefix, &ia->addr, sizeof(a->addr));
-+ a->prefix_len = ia->prefix_len;
-+ iap = inet_ntop(AF_INET6, &a->prefix.s6_addr,
-+ iabuf, sizeof(iabuf));
-+ } else {
-+ memcpy(&a->addr, &ia->addr, sizeof(a->addr));
-+ /*
-+ * RFC 5942 Section 5
-+ * We cannot assume any prefix length, nor tie the
-+ * address to an existing one as it could expire
-+ * before the address.
-+ * As such we just give it a 128 prefix.
-+ */
-+ a->prefix_len = 128;
-+ ipv6_makeprefix(&a->prefix, &a->addr, a->prefix_len);
-+ iap = inet_ntop(AF_INET6, &a->addr.s6_addr,
-+ iabuf, sizeof(iabuf));
-+ }
-+ snprintf(a->saddr, sizeof(a->saddr),
-+ "%s/%d", iap, a->prefix_len);
-+ TAILQ_INSERT_TAIL(&state->addrs, a, next);
-+ }
-+}
-+
-+static void
- dhcp6_startdiscover(void *arg)
- {
- struct interface *ifp;
-@@ -974,6 +1266,8 @@
- dhcp6_freedrop_addrs(ifp, 0, NULL);
- unlink(state->leasefile);
-
-+ dhcp6_addrequestedaddrs(ifp);
-+
- if (dhcp6_makemessage(ifp) == -1)
- syslog(LOG_ERR, "%s: dhcp6_makemessage: %m", ifp->name);
- else
-@@ -1021,11 +1315,25 @@
- dhcp6_startdiscover(ifp);
- }
-
-+
-+static int
-+dhcp6_hasprefixdelegation(struct interface *ifp)
-+{
-+ size_t i;
-+
-+ for (i = 0; i < ifp->options->ia_len; i++) {
-+ if (ifp->options->ia[i].ia_type == D6_OPTION_IA_PD)
-+ return 1;
-+ }
-+ return 0;
-+}
-+
- static void
- dhcp6_startrebind(void *arg)
- {
- struct interface *ifp;
- struct dhcp6_state *state;
-+ int pd;
-
- ifp = arg;
- eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrenew, ifp);
-@@ -1033,13 +1341,16 @@
- if (state->state == DH6S_RENEW)
- syslog(LOG_WARNING, "%s: failed to renew DHCPv6, rebinding",
- ifp->name);
-+ else
-+ syslog(LOG_INFO, "%s: rebinding prior DHCPc6 lease",
-+ ifp->name);
- state->state = DH6S_REBIND;
- state->RTC = 0;
- state->MRC = 0;
-
- /* RFC 3633 section 12.1 */
-- if (ifp->options->ia_type == D6_OPTION_IA_PD) {
-- syslog(LOG_INFO, "%s: confirming Prefix Delegation", ifp->name);
-+ pd = dhcp6_hasprefixdelegation(ifp);
-+ if (pd) {
- state->IMD = CNF_MAX_DELAY;
- state->IRT = CNF_TIMEOUT;
- state->MRT = CNF_MAX_RT;
-@@ -1054,7 +1365,7 @@
- dhcp6_sendrebind(ifp);
-
- /* RFC 3633 section 12.1 */
-- if (ifp->options->ia_type == D6_OPTION_IA_PD)
-+ if (pd)
- eloop_timeout_add_sec(ifp->ctx->eloop,
- CNF_MAX_RD, dhcp6_failrebind, ifp);
- }
-@@ -1264,46 +1575,8 @@
- 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,
-+dhcp6_findna(struct interface *ifp, uint16_t ot, const uint8_t *iaid,
- const uint8_t *d, size_t l)
- {
- struct dhcp6_state *state;
-@@ -1345,6 +1618,7 @@
- a->iface = ifp;
- a->flags = IPV6_AF_NEW | IPV6_AF_ONLINK;
- a->dadcallback = dhcp6_dadcallback;
-+ a->ia_type = ot;
- memcpy(a->iaid, iaid, sizeof(a->iaid));
- memcpy(&a->addr.s6_addr, &in6.s6_addr,
- sizeof(in6.s6_addr));
-@@ -1357,20 +1631,18 @@
- * As such we just give it a 128 prefix.
- */
- a->prefix_len = 128;
-- if (ipv6_makeprefix(&a->prefix, &a->addr,
-- a->prefix_len) == -1)
-- {
-- syslog(LOG_ERR, "%s: %m", __func__);
-- free(a);
-- continue;
-- }
-+ ipv6_makeprefix(&a->prefix, &a->addr, a->prefix_len);
- ia = inet_ntop(AF_INET6, &a->addr.s6_addr,
- iabuf, sizeof(iabuf));
- snprintf(a->saddr, sizeof(a->saddr),
- "%s/%d", ia, a->prefix_len);
-+
- TAILQ_INSERT_TAIL(&state->addrs, a, next);
-- } else
-+ } else {
-+ if (!(a->flags & IPV6_AF_ONLINK))
-+ a->flags |= IPV6_AF_ONLINK | IPV6_AF_NEW;
- a->flags &= ~IPV6_AF_STALE;
-+ }
- memcpy(&u32, p, sizeof(u32));
- a->prefix_pltime = ntohl(u32);
- p += sizeof(u32);
-@@ -1394,8 +1666,8 @@
- const uint8_t *d, size_t l)
- {
- struct dhcp6_state *state;
-- const struct dhcp6_option *o;
-- const uint8_t *p;
-+ const struct dhcp6_option *o, *ex;
-+ const uint8_t *p, *ps, *pe, *op;
- struct ipv6_addr *a;
- char iabuf[INET6_ADDRSTRLEN];
- const char *ia;
-@@ -1420,7 +1692,8 @@
- ifp->name);
- continue;
- }
-- p = D6_COPTION_DATA(o);
-+ ps = p = D6_COPTION_DATA(o);
-+ pe = ps + u32;
- memcpy(&u32, p, sizeof(u32));
- pltime = ntohl(u32);
- p += sizeof(u32);
-@@ -1431,6 +1704,7 @@
- p += sizeof(u8);
- len = u8;
- memcpy(&prefix.s6_addr, p, sizeof(prefix.s6_addr));
-+ p += sizeof(prefix.s6_addr);
-
- TAILQ_FOREACH(a, &state->addrs, next) {
- if (IN6_ARE_ADDR_EQUAL(&a->prefix, &prefix))
-@@ -1445,6 +1719,7 @@
- a->iface = ifp;
- a->flags = IPV6_AF_NEW | IPV6_AF_DELEGATEDPFX;
- a->dadcallback = dhcp6_dadcallback;
-+ a->ia_type = D6_OPTION_IA_PD;
- memcpy(a->iaid, iaid, sizeof(a->iaid));
- memcpy(&a->prefix.s6_addr,
- &prefix.s6_addr, sizeof(a->prefix.s6_addr));
-@@ -1455,24 +1730,58 @@
- "%s/%d", ia, a->prefix_len);
- TAILQ_INSERT_TAIL(&state->addrs, a, next);
- } else {
-- a->flags &= ~IPV6_AF_STALE;
-+ if (!(a->flags & IPV6_AF_DELEGATEDPFX))
-+ a->flags |= IPV6_AF_NEW | IPV6_AF_DELEGATEDPFX;
-+ a->flags &= ~(IPV6_AF_STALE | IPV6_AF_REQUEST);
- if (a->prefix_vltime != vltime)
- a->flags |= IPV6_AF_NEW;
- }
-
- a->prefix_pltime = pltime;
- a->prefix_vltime = vltime;
-+
- if (a->prefix_pltime && a->prefix_pltime < state->lowpl)
- state->lowpl = a->prefix_pltime;
- if (a->prefix_vltime && a->prefix_vltime > state->expire)
- state->expire = a->prefix_vltime;
- i++;
-+
-+ off = (size_t)(pe - p);
-+ ex = dhcp6_findoption(D6_OPTION_PD_EXCLUDE, p, off);
-+
-+ if (ex) {
-+ off = ntohs(ex->len);
-+ if (off < 2) {
-+ syslog(LOG_ERR, "%s: truncated PD Exclude",
-+ ifp->name);
-+ ex = NULL;
-+ }
-+ }
-+ if (ex) {
-+ int bytelen, bitlen;
-+
-+ op = D6_COPTION_DATA(ex);
-+ a->prefix_exclude_len = *op++;
-+ memcpy(&a->prefix_exclude, &a->prefix,
-+ sizeof(a->prefix_exclude));
-+ bytelen = a->prefix_len / NBBY;
-+ bitlen = a->prefix_len % NBBY;
-+ if (bitlen != 0)
-+ a->prefix_exclude.s6_addr[bytelen] |=
-+ *op++ >> bitlen;
-+ memcpy(a->prefix_exclude.s6_addr + bytelen + 1,
-+ op, off - 2);
-+ } else {
-+ a->prefix_exclude_len = 0;
-+ memset(&a->prefix_exclude, 0,
-+ sizeof(a->prefix_exclude));
-+ }
- }
- return i;
- }
-
- static int
--dhcp6_findia(struct interface *ifp, const uint8_t *d, size_t l,
-+dhcp6_findia(struct interface *ifp, const struct dhcp6_message *m, size_t l,
- const char *sfrom)
- {
- struct dhcp6_state *state;
-@@ -1480,25 +1789,47 @@
- const struct dhcp6_option *o;
- const uint8_t *p;
- int i, e;
-+ size_t j;
- uint32_t u32, renew, rebind;
-+ uint16_t code, ol;
- uint8_t iaid[4];
-- size_t ol;
-+ char buf[sizeof(iaid) * 3];
- struct ipv6_addr *ap, *nap;
-
-+ if (l < sizeof(*m)) {
-+ syslog(LOG_ERR, "%s: message truncated", ifp->name);
-+ errno = EINVAL;
-+ return -1;
-+ }
-+
- ifo = ifp->options;
- i = e = 0;
- state = D6_STATE(ifp);
- TAILQ_FOREACH(ap, &state->addrs, next) {
- ap->flags |= IPV6_AF_STALE;
- }
-- while ((o = dhcp6_findoption(ifo->ia_type, d, l))) {
-- ol = (size_t)((const uint8_t *)o - d);
-- l -= ol;
-- d += ol;
-+ l -= sizeof(*m);
-+ for (o = D6_FIRST_OPTION(m); l > sizeof(*o); o = D6_NEXT_OPTION(o)) {
- ol = ntohs(o->len);
-+ if (sizeof(*o) + ol > l) {
-+ errno = EINVAL;
-+ syslog(LOG_ERR, "%s: option overflow", ifp->name);
-+ break;
-+ }
- l -= sizeof(*o) + ol;
-- d += sizeof(*o) + ol;
-- u32 = ifo->ia_type == D6_OPTION_IA_TA ? 4 : 12;
-+
-+ code = ntohs(o->code);
-+ switch(code) {
-+ case D6_OPTION_IA_TA:
-+ u32 = 4;
-+ break;
-+ case D6_OPTION_IA_NA:
-+ case D6_OPTION_IA_PD:
-+ u32 = 12;
-+ break;
-+ default:
-+ continue;
-+ }
- if (ol < u32) {
- errno = EINVAL;
- syslog(LOG_ERR, "%s: IA option truncated", ifp->name);
-@@ -1509,7 +1840,25 @@
- memcpy(iaid, p, sizeof(iaid));
- p += sizeof(iaid);
- ol -= sizeof(iaid);
-- if (ifo->ia_type != D6_OPTION_IA_TA) {
-+
-+ for (j = 0; j < ifo->ia_len; j++) {
-+ if (memcmp(&ifo->ia[j].iaid, iaid, sizeof(iaid)) == 0)
-+ break;
-+ }
-+ if (j == ifo->ia_len) {
-+ syslog(LOG_DEBUG, "%s: ignoring unrequested IAID %s",
-+ ifp->name,
-+ hwaddr_ntoa(iaid, sizeof(iaid), buf, sizeof(buf)));
-+ continue;
-+ }
-+ if (ifo->ia[j].ia_type != code) {
-+ syslog(LOG_ERR, "%s: IAID %s: option type mismatch",
-+ ifp->name,
-+ hwaddr_ntoa(iaid, sizeof(iaid), buf, sizeof(buf)));
-+ continue;
-+ }
-+
-+ if (code != D6_OPTION_IA_TA) {
- memcpy(&u32, p, sizeof(u32));
- renew = ntohl(u32);
- p += sizeof(u32);
-@@ -1524,22 +1873,24 @@
- e = 1;
- continue;
- }
-- if (ifo->ia_type == D6_OPTION_IA_PD) {
-- if (dhcp6_findpd(ifp, iaid, p, ol) == 0) {
-+ if (code == D6_OPTION_IA_PD) {
-+ if (!(ifo->options & DHCPCD_NOPFXDLG) &&
-+ dhcp6_findpd(ifp, iaid, p, ol) == 0)
-+ {
- syslog(LOG_WARNING,
- "%s: %s: DHCPv6 REPLY missing Prefix",
- ifp->name, sfrom);
- continue;
- }
-- } else {
-- if (dhcp6_findna(ifp, iaid, p, ol) == 0) {
-+ } else if (!(ifo->options & DHCPCD_PFXDLGONLY)) {
-+ if (dhcp6_findna(ifp, code, iaid, p, ol) == 0) {
- syslog(LOG_WARNING,
- "%s: %s: DHCPv6 REPLY missing IA Address",
- ifp->name, sfrom);
- continue;
- }
- }
-- if (ifo->ia_type != D6_OPTION_IA_TA) {
-+ if (code != D6_OPTION_IA_TA) {
- if (renew > rebind && rebind > 0) {
- if (sfrom)
- syslog(LOG_WARNING,
-@@ -1559,11 +1910,15 @@
- }
- TAILQ_FOREACH_SAFE(ap, &state->addrs, next, nap) {
- if (ap->flags & IPV6_AF_STALE) {
-- TAILQ_REMOVE(&state->addrs, ap, next);
- if (ap->dadcallback)
- eloop_q_timeout_delete(ap->iface->ctx->eloop,
- 0, NULL, ap);
-- free(ap);
-+ if (ap->flags & IPV6_AF_REQUEST) {
-+ ap->prefix_vltime = ap->prefix_pltime = 0;
-+ } else {
-+ TAILQ_REMOVE(&state->addrs, ap, next);
-+ free(ap);
-+ }
- }
- }
- if (i == 0 && e)
-@@ -1577,25 +1932,14 @@
- const char *sfrom)
- {
- struct dhcp6_state *state;
-- const struct dhcp6_option *o;
-
- state = D6_STATE(ifp);
-- o = dhcp6_getmoption(ifp->options->ia_type, m, len);
-- if (o == NULL) {
-- if (sfrom &&
-- dhcp6_checkstatusok(ifp, m, NULL, len) != -1)
-- syslog(LOG_ERR, "%s: no IA in REPLY from %s",
-- ifp->name, sfrom);
-- return -1;
-- }
--
- if (dhcp6_checkstatusok(ifp, m, NULL, len) == -1)
- return -1;
-
- state->renew = state->rebind = state->expire = 0;
- state->lowpl = ND6_INFINITE_LIFETIME;
-- len -= (size_t)((const char *)o - (const char *)m);
-- return dhcp6_findia(ifp, (const uint8_t *)o, len, sfrom);
-+ return dhcp6_findia(ifp, m, len, sfrom);
- }
-
- static ssize_t
-@@ -1633,6 +1977,7 @@
- if (stat(state->leasefile, &st) == -1) {
- if (errno == ENOENT)
- return 0;
-+ syslog(LOG_ERR, "%s: %s: %m", ifp->name, __func__);
- return -1;
- }
- syslog(LOG_DEBUG, "%s: reading lease `%s'",
-@@ -1642,12 +1987,17 @@
- return -1;
- }
- state->new = malloc((size_t)st.st_size);
-- if (state->new == NULL)
-+ if (state->new == NULL) {
-+ syslog(LOG_ERR, "%s: %m", __func__);
- return -1;
-+ }
- state->new_len = (size_t)st.st_size;
- fd = open(state->leasefile, O_RDONLY);
-- if (fd == -1)
-+ if (fd == -1) {
-+ syslog(LOG_ERR, "%s: %s: %s: %m", ifp->name, __func__,
-+ state->leasefile);
- return -1;
-+ }
- bytes = read(fd, state->new, state->new_len);
- close(fd);
- if (bytes < (ssize_t)state->new_len) {
-@@ -1660,7 +2010,7 @@
- if (fd == -1)
- goto ex;
- if (fd == 0) {
-- syslog(LOG_INFO, "%s: lease was for different IA type",
-+ syslog(LOG_INFO, "%s: no useable IA found in lease",
- ifp->name);
- goto ex;
- }
-@@ -1705,22 +2055,39 @@
- free(state->new);
- state->new = NULL;
- state->new_len = 0;
-- unlink(state->leasefile);
-+ if (!(ifp->ctx->options & DHCPCD_DUMPLEASE))
-+ unlink(state->leasefile);
- return 0;
- }
-
-+
- static void
- dhcp6_startinit(struct interface *ifp)
- {
- struct dhcp6_state *state;
- int r;
-+ uint8_t has_ta, has_non_ta;
-+ size_t i;
-
- state = D6_STATE(ifp);
- state->state = DH6S_INIT;
- state->expire = ND6_INFINITE_LIFETIME;
- state->lowpl = ND6_INFINITE_LIFETIME;
-+
-+ dhcp6_addrequestedaddrs(ifp);
-+ has_ta = has_non_ta = 0;
-+ for (i = 0; i < ifp->options->ia_len; i++) {
-+ switch (ifp->options->ia[i].ia_type) {
-+ case D6_OPTION_IA_TA:
-+ has_ta = 1;
-+ break;
-+ default:
-+ has_non_ta = 1;
-+ }
-+ }
-+
- if (!(ifp->ctx->options & DHCPCD_TEST) &&
-- ifp->options->ia_type != D6_OPTION_IA_TA &&
-+ !(has_ta && !has_non_ta) &&
- ifp->options->reboot != 0)
- {
- r = dhcp6_readlease(ifp);
-@@ -1729,7 +2096,7 @@
- ifp->name, state->leasefile);
- else if (r != 0) {
- /* RFC 3633 section 12.1 */
-- if (ifp->options->ia_type == D6_OPTION_IA_PD)
-+ if (dhcp6_hasprefixdelegation(ifp))
- dhcp6_startrebind(ifp);
- else
- dhcp6_startconfirm(ifp);
-@@ -1740,69 +2107,28 @@
- }
-
- static struct ipv6_addr *
--dhcp6_delegate_addr(struct interface *ifp, struct ipv6_addr *prefix,
-+dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix,
- const struct if_sla *sla, struct interface *ifs)
- {
- struct dhcp6_state *state;
-- struct if_sla asla;
- struct in6_addr addr;
- struct ipv6_addr *a, *ap, *apn;
- char iabuf[INET6_ADDRSTRLEN];
- const char *ia;
-
-- state = D6_STATE(ifp);
-- if (state == NULL) {
-- ifp->if_data[IF_DATA_DHCP6] = calloc(1, sizeof(*state));
-- state = D6_STATE(ifp);
-- if (state == NULL) {
-- syslog(LOG_ERR, "%s: %m", __func__);
-+ /* RFC6603 Section 4.2 */
-+ if (ifp == ifs) {
-+ if (prefix->prefix_exclude_len == 0) {
-+ syslog(LOG_WARNING,
-+ "%s: DHCPv6 server does not support "
-+ "OPTION_PD_EXCLUDE",
-+ ifp->name);
- return NULL;
- }
--
-- TAILQ_INIT(&state->addrs);
-- state->state = DH6S_DELEGATED;
-- state->reason = "DELEGATED6";
-- }
--
-- if (sla == NULL || sla->sla_set == 0) {
-- struct interface *ifi;
-- unsigned int idx;
-- int bits;
--
-- asla.sla = ifp->index;
-- /* Work out our largest index delegating to. */
-- idx = 0;
-- TAILQ_FOREACH(ifi, ifp->ctx->ifaces, next) {
-- if (ifi != ifp && ifi->index > idx)
-- idx = ifi->index;
-- }
-- bits = ffs((int)idx);
-- if (prefix->prefix_len + bits > UINT8_MAX)
-- asla.prefix_len = UINT8_MAX;
-- else {
-- asla.prefix_len = prefix->prefix_len + (uint8_t)bits;
--
-- /* Make a 64 prefix by default, as this maks SLAAC
-- * possible. Otherwise round up to the nearest octet. */
-- if (asla.prefix_len <= 64)
-- asla.prefix_len = 64;
-- else
-- asla.prefix_len = ROUNDUP8(asla.prefix_len);
--
-- }
-- sla = &asla;
-- }
--
-- if (ipv6_userprefix(&prefix->prefix, prefix->prefix_len,
-- sla->sla, &addr, sla->prefix_len) == -1)
-- {
-- ia = inet_ntop(AF_INET6, &prefix->prefix.s6_addr,
-- iabuf, sizeof(iabuf));
-- syslog(LOG_ERR, "%s: invalid prefix %s/%d + %d/%d: %m",
-- ifp->name, ia, prefix->prefix_len,
-- sla->sla, sla->prefix_len);
-+ memcpy(&addr, &prefix->prefix_exclude, sizeof(addr));
-+ } else if (dhcp6_delegateaddr(&addr, ifp, prefix, sla) == -1)
- return NULL;
-- }
-+
-
- a = calloc(1, sizeof(*a));
- if (a == NULL) {
-@@ -1824,6 +2150,7 @@
- memcpy(&a->addr.s6_addr, &a->prefix.s6_addr, sizeof(a->addr.s6_addr));
- a->addr.s6_addr[sizeof(a->addr.s6_addr) - 1] += 1;
-
-+ state = D6_STATE(ifp);
- /* Remove any exiting address */
- TAILQ_FOREACH_SAFE(ap, &state->addrs, next, apn) {
- if (IN6_ARE_ADDR_EQUAL(&ap->addr, &a->addr)) {
-@@ -1916,7 +2243,7 @@
- abrt = 1;
- break;
- }
-- if (dhcp6_delegate_addr(ifd, ap,
-+ if (dhcp6_ifdelegateaddr(ifd, ap,
- NULL, ifp))
- k++;
- }
-@@ -1935,7 +2262,7 @@
- carrier_warned = 1;
- break;
- }
-- if (dhcp6_delegate_addr(ifd, ap,
-+ if (dhcp6_ifdelegateaddr(ifd, ap,
- sla, ifp))
- k++;
- }
-@@ -1998,7 +2325,7 @@
- dhcp6_find_delegates1, ifp);
- return 1;
- }
-- if (dhcp6_delegate_addr(ifp, ap,
-+ if (dhcp6_ifdelegateaddr(ifp, ap,
- sla, ifd))
- k++;
- }
-@@ -2225,7 +2552,7 @@
- /* PD doesn't use CONFIRM, so REBIND could
- * throw up an invalid prefix if we
- * changed link */
-- if (ifp->options->ia_type == D6_OPTION_IA_PD)
-+ if (dhcp6_hasprefixdelegation(ifp))
- dhcp6_startdiscover(ifp);
- return;
- }
-@@ -2437,10 +2764,10 @@
- if (state->expire && state->expire != ND6_INFINITE_LIFETIME)
- eloop_timeout_add_sec(ifp->ctx->eloop,
- (time_t)state->expire, dhcp6_startexpire, ifp);
-- if (ifp->options->ia_type == D6_OPTION_IA_PD)
-- dhcp6_delegate_prefix(ifp);
-
- ipv6_addaddrs(&state->addrs);
-+ dhcp6_delegate_prefix(ifp);
-+
- if (state->state == DH6S_INFORMED)
- syslog(has_new ? LOG_INFO : LOG_DEBUG,
- "%s: refresh in %"PRIu32" seconds",
-@@ -2584,6 +2911,10 @@
- add_option_mask(ifo->requestmask6, D6_OPTION_FQDN);
- }
-
-+ /* Rapid commit won't wor with Prefix Delegation Exclusion */
-+ if (dhcp6_findselfsla(ifp, NULL))
-+ del_option_mask(ifo->requestmask6, D6_OPTION_RAPID_COMMIT);
-+
- if (state->state == DH6S_INFORM) {
- add_option_mask(ifo->requestmask6, D6_OPTION_INFO_REFRESH_TIME);
- dhcp6_startinform(ifp);
-@@ -2635,7 +2966,8 @@
-
- state->state = init_state;
- snprintf(state->leasefile, sizeof(state->leasefile),
-- LEASEFILE6, ifp->name);
-+ LEASEFILE6, ifp->name,
-+ ifp->options->options & DHCPCD_PFXDLGONLY ? ".pd" : "");
-
- if (ipv6_linklocal(ifp) == NULL) {
- syslog(LOG_DEBUG,
-@@ -2790,18 +3122,21 @@
- dhcp6_env(char **env, const char *prefix, const struct interface *ifp,
- const struct dhcp6_message *m, size_t len)
- {
-- const struct dhcp6_state *state;
- const struct if_options *ifo;
- struct dhcp_opt *opt, *vo;
- const struct dhcp6_option *o;
-- size_t i, l, n;
-+ size_t i, n;
- uint16_t ol, oc;
-- char *v, *val, *pfx;
-- const struct ipv6_addr *ap;
-+ char *pfx;
- uint32_t en;
- const struct dhcpcd_ctx *ctx;
-
-- state = D6_CSTATE(ifp);
-+ if (len < sizeof(*m)) {
-+ syslog(LOG_ERR, "%s: message truncated", ifp->name);
-+ errno = EINVAL;
-+ return -1;
-+ }
-+
- n = 0;
- ifo = ifp->options;
- ctx = ifp->ctx;
-@@ -2885,64 +3220,38 @@
- }
- free(pfx);
-
-- /* It is tempting to remove this section.
-- * However, we need it at least for Delegated Prefixes
-- * (they don't have a DHCPv6 message to parse to get the addressses)
-- * and it's easier for shell scripts to see which addresses have
-- * been added */
-- if (TAILQ_FIRST(&state->addrs)) {
-- if (env) {
-- if (ifo->ia_type == D6_OPTION_IA_PD) {
-- l = strlen(prefix) +
-- strlen("_dhcp6_prefix=");
-- TAILQ_FOREACH(ap, &state->addrs, next) {
-- l += strlen(ap->saddr) + 1;
-- }
-- v = val = env[n] = malloc(l);
-- if (v == NULL) {
-- syslog(LOG_ERR, "%s: %m", __func__);
-- return -1;
-- }
-- i = (size_t)snprintf(v, l, "%s_dhcp6_prefix=",
-- prefix);
-- v += i;
-- l -= i;
-- TAILQ_FOREACH(ap, &state->addrs, next) {
-- i = strlen(ap->saddr);
-- strlcpy(v, ap->saddr, l);
-- v += i;
-- l -= i;
-- *v++ = ' ';
-- }
-- *--v = '\0';
-- } else {
-- l = strlen(prefix) +
-- strlen("_dhcp6_ip_address=");
-- TAILQ_FOREACH(ap, &state->addrs, next) {
-- l += strlen(ap->saddr) + 1;
-- }
-- v = val = env[n] = malloc(l);
-- if (v == NULL) {
-- syslog(LOG_ERR, "%s: %m", __func__);
-- return -1;
-- }
-- i = (size_t)snprintf(v, l,
-- "%s_dhcp6_ip_address=",
-- prefix);
-- v += i;
-- l -= i;
-- TAILQ_FOREACH(ap, &state->addrs, next) {
-- i = strlen(ap->saddr);
-- strlcpy(v, ap->saddr, l);
-- v += i;
-- l -= i;
-- *v++ = ' ';
-- }
-- *--v = '\0';
-- }
-- }
-- n++;
-+ return (ssize_t)n;
-+}
-+
-+int
-+dhcp6_dump(struct interface *ifp)
-+{
-+ struct dhcp6_state *state;
-+ int r;
-+
-+ ifp->if_data[IF_DATA_DHCP6] = state = calloc(1, sizeof(*state));
-+ if (state == NULL)
-+ goto eexit;
-+ TAILQ_INIT(&state->addrs);
-+ snprintf(state->leasefile, sizeof(state->leasefile),
-+ LEASEFILE6, ifp->name,
-+ ifp->options->options & DHCPCD_PFXDLGONLY ? ".pd" : "");
-+ r = dhcp6_readlease(ifp);
-+ if (r == -1 && errno == ENOENT) {
-+ strlcpy(state->leasefile, ifp->name, sizeof(state->leasefile));
-+ r = dhcp6_readlease(ifp);
- }
-+ if (r == -1) {
-+ if (errno == ENOENT)
-+ syslog(LOG_ERR, "%s: no lease to dump", ifp->name);
-+ else
-+ syslog(LOG_ERR, "%s: dhcp6_readlease: %m", ifp->name);
-+ return -1;
-+ }
-+ state->reason = "DUMP6";
-+ return script_runreason(ifp, state->reason);
-
-- return (ssize_t)n;
-+eexit:
-+ syslog(LOG_ERR, "%s: %m", __func__);
-+ return -1;
- }
-diff -urN dhcpcd-6.4.0.org/dhcp6.h dhcpcd-6.4.0/dhcp6.h
---- dhcpcd-6.4.0.org/dhcp6.h 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcp6.h 2014-07-05 21:47:22.000000000 +0200
-@@ -89,6 +89,7 @@
- #define D6_OPTION_FQDN 39
- #define D6_OPTION_POSIX_TIMEZONE 41
- #define D6_OPTION_TZDB_TIMEZONE 42
-+#define D6_OPTION_PD_EXCLUDE 67
- #define D6_OPTION_SOL_MAX_RT 82
- #define D6_OPTION_INF_MAX_RT 83
-
-@@ -225,7 +226,8 @@
- ((const uint8_t *)(o) + sizeof(struct dhcp6_option))
-
- #ifdef INET6
--void dhcp6_printoptions(const struct dhcpcd_ctx *);
-+void dhcp6_printoptions(const struct dhcpcd_ctx *,
-+ const struct dhcp_opt *, size_t);
- int dhcp6_addrexists(struct dhcpcd_ctx *, const struct ipv6_addr *);
- size_t dhcp6_find_delegates(struct interface *);
- int dhcp6_start(struct interface *, enum DH6S);
-@@ -236,15 +238,16 @@
- void dhcp6_handleifa(struct dhcpcd_ctx *, int, const char *,
- const struct in6_addr *addr, int);
- void dhcp6_drop(struct interface *, const char *);
-+int dhcp6_dump(struct interface *);
- #else
--#define dhcp6_printoptions()
- #define dhcp6_addrexists(a, b) (0)
--#define dhcp6_find_delegates(a) (0)
-+#define dhcp6_find_delegates(a)
- #define dhcp6_start(a, b) (0)
- #define dhcp6_reboot(a)
- #define dhcp6_env(a, b, c, d, e)
- #define dhcp6_free(a)
- #define dhcp6_drop(a, b)
-+#define dhcp6_dump(a) -1
- #endif
-
- #endif
-diff -urN dhcpcd-6.4.0.org/dhcp.c dhcpcd-6.4.0/dhcp.c
---- dhcpcd-6.4.0.org/dhcp.c 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcp.c 2014-07-05 21:47:22.000000000 +0200
-@@ -125,16 +125,24 @@
- static int dhcp_open(struct interface *);
-
- void
--dhcp_printoptions(const struct dhcpcd_ctx *ctx)
-+dhcp_printoptions(const struct dhcpcd_ctx *ctx,
-+ const struct dhcp_opt *opts, size_t opts_len)
- {
- const char * const *p;
-- size_t i;
-- const struct dhcp_opt *opt;
-+ size_t i, j;
-+ const struct dhcp_opt *opt, *opt2;
-
- for (p = dhcp_params; *p; p++)
- printf(" %s\n", *p);
-
-- for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++)
-+ for (i = 0, opt = ctx->dhcp_opts; i < ctx->dhcp_opts_len; i++, opt++) {
-+ for (j = 0, opt2 = opts; j < opts_len; j++, opt2++)
-+ if (opt->option == opt2->option)
-+ break;
-+ if (j == opts_len)
-+ printf("%03d %s\n", opt->option, opt->var);
-+ }
-+ for (i = 0, opt = opts; i < opts_len; i++, opt++)
- printf("%03d %s\n", opt->option, opt->var);
- }
-
-@@ -286,7 +294,7 @@
- errno = EINVAL;
- return -1;
- }
-- ocets = (cidr + 7) / 8;
-+ ocets = (cidr + 7) / NBBY;
- if (!out) {
- p += 4 + ocets;
- bytes += ((4 * 4) * 2) + 4;
-@@ -357,7 +365,7 @@
- }
- TAILQ_INSERT_TAIL(routes, rt, next);
-
-- ocets = (cidr + 7) / 8;
-+ ocets = (cidr + 7) / NBBY;
- /* If we have ocets then we have a destination and netmask */
- if (ocets > 0) {
- memcpy(&rt->dest.s_addr, p, ocets);
-@@ -943,6 +951,30 @@
- goto toobig;
- *p++ = (uint8_t)opt->option;
- }
-+ for (i = 0, opt = ifo->dhcp_override;
-+ i < ifo->dhcp_override_len;
-+ i++, opt++)
-+ {
-+ /* Check if added above */
-+ for (lp = n_params + 1; lp < p; lp++)
-+ if (*lp == (uint8_t)opt->option)
-+ break;
-+ if (lp < p)
-+ continue;
-+ if (!(opt->type & REQUEST ||
-+ has_option_mask(ifo->requestmask, opt->option)))
-+ continue;
-+ if (opt->type & NOREQ)
-+ continue;
-+ if (type == DHCP_INFORM &&
-+ (opt->option == DHO_RENEWALTIME ||
-+ opt->option == DHO_REBINDTIME))
-+ continue;
-+ len = (size_t)((p - m) + 2);
-+ if (len > sizeof(*dhcp))
-+ goto toobig;
-+ *p++ = (uint8_t)opt->option;
-+ }
- *n_params = (uint8_t)(p - n_params - 1);
- }
-
-@@ -2733,40 +2765,23 @@
- }
-
- int
--dhcp_dump(struct dhcpcd_ctx *ctx, const char *ifname)
-+dhcp_dump(struct interface *ifp)
- {
-- struct interface *ifp;
- struct dhcp_state *state;
-
-- if (ctx->ifaces == NULL) {
-- ctx->ifaces = malloc(sizeof(*ctx->ifaces));
-- if (ctx->ifaces == NULL)
-- return -1;
-- TAILQ_INIT(ctx->ifaces);
-- }
-- state = NULL;
-- ifp = calloc(1, sizeof(*ifp));
-- if (ifp == NULL)
-- goto eexit;
-- ifp->ctx = ctx;
-- TAILQ_INSERT_HEAD(ctx->ifaces, ifp, next);
- ifp->if_data[IF_DATA_DHCP] = state = calloc(1, sizeof(*state));
- if (state == NULL)
- goto eexit;
-- ifp->options = calloc(1, sizeof(*ifp->options));
-- if (ifp->options == NULL)
-- goto eexit;
-- strlcpy(ifp->name, ifname, sizeof(ifp->name));
- snprintf(state->leasefile, sizeof(state->leasefile),
- LEASEFILE, ifp->name);
- state->new = read_lease(ifp);
- if (state->new == NULL && errno == ENOENT) {
-- strlcpy(state->leasefile, ifname, sizeof(state->leasefile));
-+ strlcpy(state->leasefile, ifp->name, sizeof(state->leasefile));
- state->new = read_lease(ifp);
- }
- if (state->new == NULL) {
- if (errno == ENOENT)
-- syslog(LOG_ERR, "%s: no lease to dump", ifname);
-+ syslog(LOG_ERR, "%s: no lease to dump", ifp->name);
- return -1;
- }
- state->reason = "DUMP";
-@@ -3015,13 +3030,22 @@
- if (!(ifp->options->options & DHCPCD_IPV4))
- return;
-
-- tv.tv_sec = DHCP_MIN_DELAY;
-- tv.tv_usec = (suseconds_t)arc4random_uniform(
-- (DHCP_MAX_DELAY - DHCP_MIN_DELAY) * 1000000);
-- timernorm(&tv);
-- syslog(LOG_DEBUG,
-- "%s: delaying DHCP for %0.1f seconds",
-- ifp->name, timeval_to_double(&tv));
-+ /* No point in delaying a static configuration */
-+ if (ifp->options->options & DHCPCD_STATIC &&
-+ !(ifp->options->options & DHCPCD_INFORM))
-+ {
-+ tv.tv_sec = 0;
-+ tv.tv_usec = 0;
-+ } else {
-+ tv.tv_sec = DHCP_MIN_DELAY;
-+ tv.tv_usec = (suseconds_t)arc4random_uniform(
-+ (DHCP_MAX_DELAY - DHCP_MIN_DELAY) * 1000000);
-+ timernorm(&tv);
-+ syslog(LOG_DEBUG,
-+ "%s: delaying DHCP for %0.1f seconds",
-+ ifp->name, timeval_to_double(&tv));
-+ }
-+
- eloop_timeout_add_tv(ifp->ctx->eloop, &tv, dhcp_start1, ifp);
- }
-
-diff -urN dhcpcd-6.4.0.org/dhcpcd.8.in dhcpcd-6.4.0/dhcpcd.8.in
---- dhcpcd-6.4.0.org/dhcpcd.8.in 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcpcd.8.in 2014-07-05 21:47:22.000000000 +0200
-@@ -22,7 +22,7 @@
- .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- .\" SUCH DAMAGE.
- .\"
--.Dd June 2, 2014
-+.Dd July 4, 2014
- .Dt DHCPCD 8
- .Os
- .Sh NAME
-@@ -68,6 +68,10 @@
- .Fl U, Fl Fl dumplease
- .Ar interface
- .Nm
-+.Fl Fl pfxdlgonly
-+.Nm
-+.Fl Fl nopfxdlg
-+.Nm
- .Fl Fl version
- .Nm
- .Fl x , Fl Fl exit
-@@ -75,7 +79,7 @@
- .Sh DESCRIPTION
- .Nm
- is an implementation of the DHCP client specified in
--.%R RFC 2131 .
-+.Li RFC 2131 .
- .Nm
- gets the host information
- .Po
-@@ -103,17 +107,17 @@
- .Pp
- .Nm
- is also an implementation of the BOOTP client specified in
--.%R RFC 951 .
-+.Li RFC 951 .
- .Pp
- .Nm
- is also an implementation of the IPv6 Router Solicitor as specified in
--.%R RFC 4861
-+.Li RFC 4861
- and
--.%R RFC 6106 .
-+.Li RFC 6106 .
- .Pp
- .Nm
- is also an implemenation of the DHCPv6 client as specified in
--.%R RFC 3315 .
-+.Li RFC 3315 .
- By default,
- .Nm
- only starts DHCPv6 when instructed to do so by an IPV6 Router Advertisement.
-@@ -211,7 +215,7 @@
- .Pa @SCRIPT@ .
- .It Fl D , Fl Fl duid
- Generate an
--.%R RFC 4361
-+.Li RFC 4361
- compliant clientid.
- This requires persistent storage and not all DHCP servers work with it so it
- is not enabled by default.
-@@ -259,7 +263,7 @@
- itself never does any DNS updates.
- .Nm
- encodes the FQDN hostname as specified in
--.%R RFC1035 .
-+.Li RFC1035 .
- .It Fl f , Fl Fl config Ar file
- Specify a config to load instead of
- .Pa @SYSCONFDIR@/dhcpcd.conf .
-@@ -614,6 +618,30 @@
- so that
- .Nm
- knows which process to signal.
-+.Pp
-+.Li RFC3633
-+DHCPv6 Prefix Delegation does not work in the same state or session as
-+Normal or Temporary Addresses.
-+.Nm
-+is designed for a single state per protocol and as such
-+.Li draft-ietf-dhc-dhcpv6-stateful-issues-06
-+is supported by default, but that is not a published RFC yet.
-+To allow RFC conformance,
-+.Nm
-+supports the
-+.Fl Fl pfxdlgonly
-+and
-+.Fl Fl nopfxdlg
-+options which allow the spawning of two
-+.Nm
-+instances to separate the Prefix Delegation state from the others.
-+You may wish to disable
-+.Xr dhcpcd-run-hooks 8
-+on the
-+.Fl Fl pfxdlgonly
-+instance using the
-+.Fl Fl script \"\"
-+option.
- .Sh FILES
- .Bl -ohang
- .It Pa @SYSCONFDIR@/dhcpcd.conf
-@@ -671,7 +699,8 @@
- RFC\ 3004, RFC\ 3118, RFC\ 3203, RFC\ 3315, RFC\ 3361, RFC\ 3633, RFC\ 3396,
- RFC\ 3397, RFC\ 3442, RFC\ 3495, RFC\ 3925, RFC\ 3927, RFC\ 4039, RFC\ 4075,
- RFC\ 4242, RFC\ 4361, RFC\ 4390, RFC\ 4702, RFC\ 4074, RFC\ 4861, RFC\ 4833,
--RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106, RFC\ 6334, RFC\ 6704, RFC\ 7217.
-+RFC\ 5227, RFC\ 5942, RFC\ 5969, RFC\ 6106, RFC\ 6334, RFC\ 6603, RFC\ 6704,
-+RFC\ 7217.
- .Sh AUTHORS
- .An Roy Marples Aq Mt roy at marples.name
- .Sh BUGS
-diff -urN dhcpcd-6.4.0.org/dhcpcd.c dhcpcd-6.4.0/dhcpcd.c
---- dhcpcd-6.4.0.org/dhcpcd.c 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcpcd.c 2014-07-05 21:47:22.000000000 +0200
-@@ -139,14 +139,14 @@
- struct dhcp_opt *opt;
-
- if (ctx->ifac) {
-- for (ctx->ifac--; ctx->ifac >= 0; ctx->ifac--)
-- free(ctx->ifav[ctx->ifac]);
-+ for (; ctx->ifac > 0; ctx->ifac--)
-+ free(ctx->ifav[ctx->ifac - 1]);
- free(ctx->ifav);
- ctx->ifav = NULL;
- }
- if (ctx->ifdc) {
-- for (ctx->ifdc--; ctx->ifdc >= 0; ctx->ifdc--)
-- free(ctx->ifdv[ctx->ifdc]);
-+ for (; ctx->ifdc > 0; ctx->ifdc--)
-+ free(ctx->ifdv[ctx->ifdc - 1]);
- free(ctx->ifdv);
- ctx->ifdv = NULL;
- }
-@@ -323,6 +323,9 @@
- {
- struct if_options *ifo = ifp->options;
- int ra_global, ra_iface;
-+#ifdef INET6
-+ size_t i;
-+#endif
-
- /* Do any platform specific configuration */
- if_conf(ifp);
-@@ -339,7 +342,7 @@
- ifo->options &= ~(DHCPCD_ARP | DHCPCD_IPV4LL);
- if (!(ifp->flags & (IFF_POINTOPOINT | IFF_LOOPBACK | IFF_MULTICAST)))
- ifo->options &= ~DHCPCD_IPV6RS;
-- if (ifo->options & DHCPCD_LINK && if_carrier(ifp) == LINK_UNKNOWN)
-+ if (ifo->options & DHCPCD_LINK && ifp->carrier == LINK_UNKNOWN)
- ifo->options &= ~DHCPCD_LINK;
-
- if (ifo->metric != -1)
-@@ -431,17 +434,27 @@
- }
-
- #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;
-+ if (ifo->options & DHCPCD_IPV6) {
-+ if (ifo->ia == NULL) {
-+ ifo->ia = malloc(sizeof(*ifo->ia));
-+ if (ifo->ia == NULL)
-+ syslog(LOG_ERR, "%s: %m", __func__);
-+ else {
-+ ifo->ia_len = 1;
-+ ifo->ia->ia_type = D6_OPTION_IA_NA;
-+ memcpy(ifo->ia->iaid, ifo->iaid,
-+ sizeof(ifo->iaid));
-+ memset(&ifo->ia->addr, 0,
-+ sizeof(ifo->ia->addr));
-+ ifo->ia->sla = NULL;
-+ ifo->ia->sla_len = 0;
-+ }
-+ } else {
-+ for (i = 0; i < ifo->ia_len; i++) {
-+ if (!ifo->ia[i].iaid_set)
-+ memcpy(ifo->ia->iaid, ifo->iaid,
-+ sizeof(ifo->iaid));
-+ }
- }
- }
- #endif
-@@ -493,10 +506,23 @@
- if (ifp == NULL || !(ifp->options->options & DHCPCD_LINK))
- return;
-
-- if (carrier == LINK_UNKNOWN)
-+ switch(carrier) {
-+ case LINK_UNKNOWN:
- carrier = if_carrier(ifp); /* will set ifp->flags */
-- else
-+ break;
-+ case LINK_UP:
-+ /* we have a carrier! however, we need to ignore the flags
-+ * set in the kernel message as sometimes this message is
-+ * reported before IFF_UP is set by the kernel even though
-+ * dhcpcd has already set it.
-+ *
-+ * So we check the flags now. If IFF_UP is still not set
-+ * then we should expect an accompanying link_down message */
-+ if_setflag(ifp, 0); /* will set ifp->flags */
-+ break;
-+ default:
- ifp->flags = flags;
-+ }
-
- if (carrier == LINK_UNKNOWN)
- syslog(LOG_ERR, "%s: carrier_status: %m", ifname);
-@@ -561,32 +587,33 @@
- ifp->name, ifn->name);
- }
-
--void
--dhcpcd_startinterface(void *arg)
-+static void
-+pre_start(struct interface *ifp)
- {
-- struct interface *ifp = arg;
-- struct if_options *ifo = ifp->options;
-- size_t i;
-- char buf[DUID_LEN * 3];
-
- /* Add our link-local address before upping the interface
- * so our RFC7217 address beats the hwaddr based one.
- * This is also a safety check incase it was ripped out
- * from under us. */
-- if (ifo->options & DHCPCD_IPV6 && ipv6_start(ifp) == -1) {
-+ if (ifp->options->options & DHCPCD_IPV6 && ipv6_start(ifp) == -1) {
- syslog(LOG_ERR, "%s: ipv6_start: %m", ifp->name);
-- ifo->options &= DHCPCD_IPV6;
-+ ifp->options->options &= DHCPCD_IPV6;
- }
-+}
-
-- if (!(ifp->flags & IFF_UP) && if_carrier(ifp) != LINK_UNKNOWN) {
-- if (if_up(ifp) == -1)
-- syslog(LOG_ERR, "%s: if_up: %m",
-- ifp->name);
-- }
-+void
-+dhcpcd_startinterface(void *arg)
-+{
-+ struct interface *ifp = arg;
-+ struct if_options *ifo = ifp->options;
-+ size_t i;
-+ char buf[DUID_LEN * 3];
-
-- if (ifp->carrier == LINK_UNKNOWN)
-- dhcpcd_handlecarrier(ifp->ctx, LINK_UNKNOWN, 0, ifp->name);
-- if (ifp->carrier == LINK_DOWN) {
-+ pre_start(ifp);
-+ if (if_up(ifp) == -1)
-+ syslog(LOG_ERR, "%s: if_up: %m", ifp->name);
-+
-+ if (ifp->carrier == LINK_DOWN && ifo->options & DHCPCD_LINK) {
- syslog(LOG_INFO, "%s: waiting for carrier", ifp->name);
- return;
- }
-@@ -621,10 +648,12 @@
-
- if (ifo->options & DHCPCD_IPV6) {
- if (ifo->options & DHCPCD_IPV6RS &&
-- !(ifo->options & DHCPCD_INFORM))
-+ !(ifo->options & (DHCPCD_INFORM | DHCPCD_PFXDLGONLY)))
- ipv6nd_startrs(ifp);
-
-- if (!(ifo->options & DHCPCD_IPV6RS)) {
-+ if (!(ifo->options & DHCPCD_IPV6RS) ||
-+ ifo->options & DHCPCD_IA_FORCED)
-+ {
- ssize_t nolease;
-
- if (ifo->options & DHCPCD_IA_FORCED)
-@@ -651,6 +680,8 @@
- "%s: dhcp6_start: %m", ifp->name);
- }
- }
-+ if (ifo->options & DHCPCD_PFXDLGONLY)
-+ return;
-
- if (ifo->options & DHCPCD_IPV4)
- dhcp_start(ifp);
-@@ -700,31 +731,17 @@
- static void
- run_preinit(struct interface *ifp)
- {
-- const char *reason;
-
-- reason = NULL; /* appease gcc */
-- if (ifp->options->options & DHCPCD_LINK) {
-- switch (if_carrier(ifp)) {
-- case LINK_DOWN:
-- ifp->carrier = LINK_DOWN;
-- reason = "NOCARRIER";
-- break;
-- case LINK_UP:
-- ifp->carrier = LINK_UP;
-- reason = "CARRIER";
-- break;
-- default:
-- ifp->carrier = LINK_UNKNOWN;
-- return;
-- }
-- } else
-- ifp->carrier = LINK_UNKNOWN;
-+ pre_start(ifp);
-+ if (ifp->ctx->options & DHCPCD_TEST)
-+ return;
-
-- if (!(ifp->ctx->options & DHCPCD_TEST))
-- script_runreason(ifp, "PREINIT");
-+ script_runreason(ifp, "PREINIT");
-
-- if (ifp->carrier != LINK_UNKNOWN && !(ifp->ctx->options & DHCPCD_TEST))
-- script_runreason(ifp, reason);
-+ if (ifp->carrier != LINK_UNKNOWN &&
-+ ifp->options->options & DHCPCD_LINK)
-+ script_runreason(ifp,
-+ ifp->carrier == LINK_UP ? "CARRIER" : "NOCARRIER");
- }
-
- int
-@@ -732,7 +749,7 @@
- {
- struct dhcpcd_ctx *ctx;
- struct if_head *ifs;
-- struct interface *ifp, *ifn, *ifl = NULL;
-+ struct interface *ifp, *iff, *ifn;
- const char * const argv[] = { ifname };
- int i;
-
-@@ -743,6 +760,7 @@
- errno = ESRCH;
- return -1;
- }
-+ syslog(LOG_DEBUG, "%s: interface departed", ifp->name);
- ifp->options->options |= DHCPCD_DEPARTED;
- stop_interface(ifp);
- return 0;
-@@ -764,22 +782,24 @@
- continue;
- i = 0;
- /* Check if we already have the interface */
-- ifl = if_find(ctx, ifp->name);
-- if (ifl) {
-+ iff = if_find(ctx, ifp->name);
-+ if (iff) {
-+ syslog(LOG_DEBUG, "%s: interface updated", iff->name);
- /* The flags and hwaddr could have changed */
-- ifl->flags = ifp->flags;
-- ifl->hwlen = ifp->hwlen;
-+ iff->flags = ifp->flags;
-+ iff->hwlen = ifp->hwlen;
- if (ifp->hwlen != 0)
-- memcpy(ifl->hwaddr, ifp->hwaddr, ifl->hwlen);
-+ memcpy(iff->hwaddr, ifp->hwaddr, iff->hwlen);
- } else {
-+ syslog(LOG_DEBUG, "%s: interface added", ifp->name);
- TAILQ_REMOVE(ifs, ifp, next);
- TAILQ_INSERT_TAIL(ctx->ifaces, ifp, next);
-- }
-- if (action > 0) {
- init_state(ifp, ctx->argc, ctx->argv);
- run_preinit(ifp);
-- dhcpcd_startinterface(ifp);
-+ iff = ifp;
- }
-+ if (action > 0)
-+ dhcpcd_startinterface(iff);
- }
-
- /* Free our discovered list */
-@@ -1264,6 +1284,8 @@
- ctx.ifv = argv + optind;
-
- ifo = read_config(&ctx, NULL, NULL, NULL);
-+ if (ifo == NULL)
-+ goto exit_failure;
- opt = add_options(&ctx, NULL, ifo, argc, argv);
- if (opt != 1) {
- if (opt == 0)
-@@ -1272,17 +1294,26 @@
- }
- if (i == 3) {
- printf("Interface options:\n");
-+ if (optind == argc - 1) {
-+ free_options(ifo);
-+ ifo = read_config(&ctx, argv[optind], NULL, NULL);
-+ if (ifo == NULL)
-+ goto exit_failure;
-+ add_options(&ctx, NULL, ifo, argc, argv);
-+ }
- if_printoptions();
- #ifdef INET
- if (family == 0 || family == AF_INET) {
- printf("\nDHCPv4 options:\n");
-- dhcp_printoptions(&ctx);
-+ dhcp_printoptions(&ctx,
-+ ifo->dhcp_override, ifo->dhcp_override_len);
- }
- #endif
- #ifdef INET6
- if (family == 0 || family == AF_INET6) {
- printf("\nDHCPv6 options:\n");
-- dhcp6_printoptions(&ctx);
-+ dhcp6_printoptions(&ctx,
-+ ifo->dhcp6_override, ifo->dhcp6_override_len);
- }
- #endif
- goto exit_success;
-@@ -1341,9 +1372,10 @@
- }
- snprintf(pidfile, sizeof(pidfile),
- PIDFILE, "-", argv[optind], per);
-- }
-- else {
-- snprintf(pidfile, sizeof(pidfile), PIDFILE, "", "", "");
-+ } else {
-+ snprintf(pidfile, sizeof(pidfile), PIDFILE,
-+ ctx.options & DHCPCD_PFXDLGONLY ? ".pd" : "",
-+ "", "");
- ctx.options |= DHCPCD_MASTER;
- }
- }
-@@ -1351,18 +1383,52 @@
- if (chdir("/") == -1)
- syslog(LOG_ERR, "chdir `/': %m");
-
-+ /* Freeing allocated addresses from dumping leases can trigger
-+ * eloop removals as well, so init here. */
-+ ctx.eloop = eloop_init();
-+ if (ctx.eloop == NULL) {
-+ syslog(LOG_ERR, "%s: %m", __func__);
-+ goto exit_failure;
-+ }
-+
- if (ctx.options & DHCPCD_DUMPLEASE) {
- if (optind != argc - 1) {
- syslog(LOG_ERR, "dumplease requires an interface");
- goto exit_failure;
- }
-- if (dhcp_dump(&ctx, argv[optind]) == -1)
-+ i = 0;
-+ /* We need to try and find the interface so we can
-+ * load the hardware address to compare automated IAID */
-+ ctx.ifaces = if_discover(&ctx, 1, argv + optind);
-+ if (ctx.ifaces == NULL)
-+ goto exit_failure;
-+ ifp = TAILQ_FIRST(ctx.ifaces);
-+ if (ifp == NULL) {
-+ ifp = calloc(1, sizeof(*ifp));
-+ if (ifp == NULL) {
-+ syslog(LOG_ERR, "%s: %m", __func__);
-+ goto exit_failure;
-+ }
-+ strlcpy(ifp->name, argv[optind], sizeof(ifp->name));
-+ ifp->ctx = &ctx;
-+ TAILQ_INSERT_HEAD(ctx.ifaces, ifp, next);
-+ }
-+ configure_interface(ifp, ctx.argc, ctx.argv);
-+ if (family == 0 || family == AF_INET) {
-+ if (dhcp_dump(ifp) == -1)
-+ i = 1;
-+ }
-+ if (family == 0 || family == AF_INET6) {
-+ if (dhcp6_dump(ifp) == -1)
-+ i = 1;
-+ }
-+ if (i == -1)
- goto exit_failure;
- goto exit_success;
- }
-
- #ifdef USE_SIGNALS
-- if (!(ctx.options & DHCPCD_TEST) &&
-+ if (!(ctx.options & (DHCPCD_TEST | DHCPCD_PFXDLGONLY)) &&
- (sig == 0 || ctx.ifc != 0))
- {
- #endif
-@@ -1396,12 +1462,6 @@
- syslog(LOG_WARNING,
- PACKAGE " will not work correctly unless run as root");
-
-- ctx.eloop = eloop_init();
-- if (ctx.eloop == NULL) {
-- syslog(LOG_ERR, "%s: %m", __func__);
-- goto exit_failure;
-- }
--
- #ifdef USE_SIGNALS
- if (sig != 0) {
- pid = read_pid(pidfile);
-@@ -1484,7 +1544,7 @@
- }
-
-
-- if (ctx.options & DHCPCD_MASTER) {
-+ if (ctx.options & DHCPCD_MASTER && !(ctx.options & DHCPCD_PFXDLGONLY)) {
- if (control_start(&ctx, NULL) == -1)
- syslog(LOG_ERR, "control_start: %m");
- }
-@@ -1622,7 +1682,6 @@
-
- free_options(ifo);
- free_globals(&ctx);
-- if_rarestore(&ctx);
- ipv4_ctxfree(&ctx);
- ipv6_ctxfree(&ctx);
- dev_stop(&ctx, !(ctx.options & DHCPCD_FORKED));
-diff -urN dhcpcd-6.4.0.org/dhcpcd.conf.5.in dhcpcd-6.4.0/dhcpcd.conf.5.in
---- dhcpcd-6.4.0.org/dhcpcd.conf.5.in 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcpcd.conf.5.in 2014-07-05 21:47:22.000000000 +0200
-@@ -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 July 4, 2014
- .Dt DHCPCD.CONF 5
- .Os
- .Sh NAME
-@@ -214,7 +214,7 @@
- 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
- Request a DHCPv6 Normal Address for
- .Ar iaid .
- .Ar iaid
-@@ -230,7 +230,7 @@
- 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
-@@ -250,7 +250,10 @@
- and
- .Ar sla_id .
- Each assigned address will have a suffix of 1.
--You cannot assign a prefix to the requesting interface.
-+You cannot assign a prefix to the requesting interface unless the
-+DHCPv6 server supports
-+.Li RFC6603
-+Prefix Exclude Option.
- .Nm dhcpcd
- has to be running for all the interfaces it is delegating to.
- A default
-@@ -290,6 +293,12 @@
- .D1 interface eth1
- .D1 ipv4
- .D1 ipv6rs
-+.Pp
-+Using this option with other IA options in the same interface block is not
-+currently RFC conformant.
-+Please see the
-+.Li BUGS
-+section below.
- .It Ic ipv4only
- Only configure IPv4.
- .It Ic ipv6only
-@@ -457,6 +466,9 @@
- .Ar ssid .
- .It Ic slaac Op Ar hwaddr | Ar private
- Selects the interface identifier used for SLAAC generated IPv6 addresses.
-+If
-+.Ar private
-+is used, a RFC7217 address is generated.
- .It Ic static Ar value
- Configures a static
- .Ar value .
-@@ -739,11 +751,21 @@
- .Sh AUTHORS
- .An Roy Marples Aq Mt roy at marples.name
- .Sh BUGS
--When configuring DHCPv6 you can only select one IA type.
--I can't think of a use case where you would want different types,
--so if you have one then please bring it up for discussion on the
--.Aq Mt dhcpcd-discuss at marples.name
--mailing list.
-+Combining different DHCPv6 IA options in the same interface block is not
-+currently RFC conformant.
-+See
-+.Lk http://datatracker.ietf.org/doc/draft-ietf-dhc-dhcpv6-stateful-issues
-+for details.
-+.Nm dhcpcd
-+strives to comply with this document and will be updated when finally published.
-+To enable RFC conformance, spawn separate
-+.Nm dhcpcd
-+instances using the
-+.Fl Fl pfxdlgonly
-+and
-+.Fl Fl nopfxdlg
-+options as described in
-+.Xr dhcpcd 8 .
- .Pp
- Please report them to
- .Lk http://roy.marples.name/projects/dhcpcd
-diff -urN dhcpcd-6.4.0.org/dhcpcd-definitions.conf dhcpcd-6.4.0/dhcpcd-definitions.conf
---- dhcpcd-6.4.0.org/dhcpcd-definitions.conf 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcpcd-definitions.conf 2014-07-05 21:47:22.000000000 +0200
-@@ -360,6 +360,7 @@
- embed uint32 vltime
- embed ip6address prefix
- encap 13 option
-+encap 67 option
-
- # DHCPv6 Network Information Service Options, RFC3898
- define6 27 array ip6address nis_servers
-@@ -463,6 +464,11 @@
- # DHCPv6 AFTR-Name, RFC6334
- define6 64 domain aftr_name
-
-+# DHCPv6 Prefix Exclude Option, RFC6603
-+define6 67 embed pd_exclude
-+embed byte prefix_len
-+embed binhex subnetID
-+
- # DHCPv6 Home Info Discovery in MIPv6, RFC6610
- define6 69 encap mip6_idinf
- encap 71 option
-diff -urN dhcpcd-6.4.0.org/dhcpcd.h dhcpcd-6.4.0/dhcpcd.h
---- dhcpcd-6.4.0.org/dhcpcd.h 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcpcd.h 2014-07-05 21:47:22.000000000 +0200
-@@ -123,11 +123,8 @@
- struct dhcp_opt *dhcp6_opts;
- size_t dhcp6_opts_len;
- struct ipv6_ctx *ipv6;
-- char **ra_restore;
-- size_t ra_restore_len;
- #ifndef __linux__
- int ra_global;
-- int ra_kernel_set;
- #endif
- #endif /* INET6 */
-
-diff -urN dhcpcd-6.4.0.org/dhcpcd-hooks/02-dump dhcpcd-6.4.0/dhcpcd-hooks/02-dump
---- dhcpcd-6.4.0.org/dhcpcd-hooks/02-dump 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcpcd-hooks/02-dump 2014-07-05 21:47:22.000000000 +0200
-@@ -1,6 +1,8 @@
- # Just echo our DHCP options we have
-
--if [ "$reason" = "DUMP" ]; then
-+case "$reason" in
-+DUMP|DUMP6)
- set | sed -ne 's/^new_//p' | sort
- exit 0
--fi
-+ ;;
-+esac
-diff -urN dhcpcd-6.4.0.org/dhcpcd-hooks/20-resolv.conf dhcpcd-6.4.0/dhcpcd-hooks/20-resolv.conf
---- dhcpcd-6.4.0.org/dhcpcd-hooks/20-resolv.conf 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcpcd-hooks/20-resolv.conf 2014-07-05 21:47:22.000000000 +0200
-@@ -70,7 +70,7 @@
-
- add_resolv_conf()
- {
-- local x= conf="$signature$NL" i=${ra_count:-0} ra=
-+ local x= conf="$signature$NL" i=${ra_count:-0} ra= warn=true
-
- while [ $i -ne 0 ]; do
- eval ra=\$ra${i}_rdnss
-@@ -101,24 +101,23 @@
-
- if [ -n "$new_domain_name" ]; then
- set -- $new_domain_name
-- new_domain_name="$1"
-- if valid_domainname "$new_domain_name"; then
-- conf="${conf}domain $new_domain_name$NL"
-+ if valid_domainname "$1"; then
-+ conf="${conf}domain $1$NL"
- else
-- syslog err "Invalid domain name: $new_domain_name"
-+ syslog err "Invalid domain name: $1"
- fi
-- # Support RFC violating search in domain
-- if [ -z "$new_domain_search" -a -n "$2" ]; then
-- new_domain_search="$*"
-+ # If there is no search this, make this one
-+ if [ -z "$new_domain_search" ]; then
-+ new_domain_search="$new_domain_name"
-+ [ "$new_domain_name" = "$1" ] && warn=true
- fi
- fi
-- if [ -n "$new_domain_search" -a \
-- "$new_domain_search" != "$new_domain_name" ]
-- then
-+ if [ -n "$new_domain_search" ]; then
- if valid_domainname_list $new_domain_search; then
- conf="${conf}search $new_domain_search$NL"
-- else
-- syslog err "Invalid domain name in list: $new_domain_search"
-+ elif ! $warn; then
-+ syslog err "Invalid domain name in list:" \
-+ "$new_domain_search"
- fi
- fi
- for x in ${new_domain_name_servers}; do
-diff -urN dhcpcd-6.4.0.org/dhcpcd-hooks/Makefile dhcpcd-6.4.0/dhcpcd-hooks/Makefile
---- dhcpcd-6.4.0.org/dhcpcd-hooks/Makefile 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcpcd-hooks/Makefile 2014-07-05 21:47:22.000000000 +0200
-@@ -25,7 +25,7 @@
-
- install: proginstall
-
--import:
-+import: ${HOOKSCRIPTS}
- ${INSTALL} -d /tmp/${DISTPREFIX}/dhcpcd-hooks
- for x in ${SCRIPTS}; do \
- t="/tmp/${DISTPREFIX}/dhcpcd-hooks/$$x"; \
-diff -urN dhcpcd-6.4.0.org/dhcp-common.c dhcpcd-6.4.0/dhcp-common.c
---- dhcpcd-6.4.0.org/dhcp-common.c 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcp-common.c 2014-07-05 21:47:22.000000000 +0200
-@@ -86,6 +86,7 @@
-
- int
- make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
-+ const struct dhcp_opt *odopts, size_t odopts_len,
- uint8_t *mask, const char *opts, int add)
- {
- char *token, *o, *p, *t;
-@@ -94,14 +95,14 @@
- unsigned int n;
- size_t i;
-
-- o = p = strdup(opts);
- if (opts == NULL)
- return -1;
-+ o = p = strdup(opts);
- while ((token = strsep(&p, ", "))) {
- if (*token == '\0')
- continue;
-- for (i = 0, opt = dopts; i < dopts_len; i++, opt++) {
-- match = 0;
-+ match = 0;
-+ for (i = 0, opt = odopts; i < odopts_len; i++, opt++) {
- if (strcmp(opt->var, token) == 0)
- match = 1;
- else {
-@@ -111,26 +112,40 @@
- if (opt->option == n)
- match = 1;
- }
-- if (match) {
-- if (add == 2 && !(opt->type & ADDRIPV4)) {
-- free(o);
-- errno = EINVAL;
-- return -1;
-- }
-- if (add == 1 || add == 2)
-- add_option_mask(mask,
-- opt->option);
-- else
-- del_option_mask(mask,
-- opt->option);
-+ if (match)
- break;
-+ }
-+ if (match == 0) {
-+ for (i = 0, opt = dopts; i < dopts_len; i++, opt++) {
-+ if (strcmp(opt->var, token) == 0)
-+ match = 1;
-+ else {
-+ errno = 0;
-+ n = (unsigned int)strtol(token, &t, 0);
-+ if (errno == 0 && !*t)
-+ if (opt->option == n)
-+ match = 1;
-+ }
-+ if (match)
-+ break;
- }
- }
-- if (!opt->option) {
-+ if (!match || !opt->option) {
- free(o);
- errno = ENOENT;
- return -1;
- }
-+ if (add == 2 && !(opt->type & ADDRIPV4)) {
-+ free(o);
-+ errno = EINVAL;
-+ return -1;
-+ }
-+ if (add == 1 || add == 2)
-+ add_option_mask(mask,
-+ opt->option);
-+ else
-+ del_option_mask(mask,
-+ opt->option);
- }
- free(o);
- return 0;
-diff -urN dhcpcd-6.4.0.org/dhcp-common.h dhcpcd-6.4.0/dhcp-common.h
---- dhcpcd-6.4.0.org/dhcp-common.h 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcp-common.h 2014-07-05 21:47:22.000000000 +0200
-@@ -88,6 +88,7 @@
- #define del_option_mask(var, val) (var[val >> 3] &= ~(1 << (val & 7)))
- #define has_option_mask(var, val) (var[val >>3] & (1 << (val & 7)))
- int make_option_mask(const struct dhcp_opt *, size_t,
-+ const struct dhcp_opt *, size_t,
- uint8_t *, const char *, int);
-
- size_t encode_rfc1035(const char *src, uint8_t *dst);
-diff -urN dhcpcd-6.4.0.org/dhcp.h dhcpcd-6.4.0/dhcp.h
---- dhcpcd-6.4.0.org/dhcp.h 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/dhcp.h 2014-07-05 21:47:22.000000000 +0200
-@@ -250,7 +250,8 @@
- ssize_t decode_rfc3442(char *, size_t, const uint8_t *p, size_t);
- ssize_t decode_rfc5969(char *, size_t, const uint8_t *p, size_t);
-
--void dhcp_printoptions(const struct dhcpcd_ctx *);
-+void dhcp_printoptions(const struct dhcpcd_ctx *,
-+ const struct dhcp_opt *, size_t);
- int get_option_addr(struct dhcpcd_ctx *,struct in_addr *,
- const struct dhcp_message *, uint8_t);
- #define is_bootp(i, m) ((m) && \
-@@ -285,16 +286,15 @@
- void dhcp_reboot_newopts(struct interface *, unsigned long long);
- void dhcp_close(struct interface *);
- void dhcp_free(struct interface *);
--int dhcp_dump(struct dhcpcd_ctx *, const char *);
-+int dhcp_dump(struct interface *);
- #else
--#define dhcp_printoptions
- #define dhcp_drop(a, b)
- #define dhcp_start(a) {}
- #define dhcp_reboot(a, b) b = b
- #define dhcp_reboot_newopts(a, b)
- #define dhcp_close(a)
- #define dhcp_free(a)
--#define dhcp_dump(a, b) -1
-+#define dhcp_dump(a) -1
- #endif
-
- #endif
-diff -urN dhcpcd-6.4.0.org/if-bsd.c dhcpcd-6.4.0/if-bsd.c
---- dhcpcd-6.4.0.org/if-bsd.c 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/if-bsd.c 2014-07-05 21:47:22.000000000 +0200
-@@ -1019,45 +1019,6 @@
- return flags;
- }
-
--void
--if_rarestore(struct dhcpcd_ctx *ctx)
--{
--
-- if (ctx->options & DHCPCD_FORKED)
-- return;
--
-- for (; ctx->ra_restore_len > 0; ctx->ra_restore_len--) {
--#ifdef ND6_IFF_ACCEPT_RTADV
-- if (!(ctx->options & DHCPCD_FORKED)) {
-- syslog(LOG_DEBUG,
-- "%s: restoring kernel IPv6 RA support",
-- ctx->ra_restore[ctx->ra_restore_len - 1]);
-- if (set_if_nd6_flag(
-- ctx->ra_restore[ctx->ra_restore_len -1],
-- ND6_IFF_ACCEPT_RTADV) == -1)
-- syslog(LOG_ERR, "%s: set_if_nd6_flag: %m",
-- ctx->ra_restore[ctx->ra_restore_len - 1]);
--#ifdef ND6_IFF_OVERRIDE_RTADV
-- if (ctx->ra_kernel_set == 0 && del_if_nd6_flag(
-- ctx->ra_restore[ctx->ra_restore_len -1],
-- ND6_IFF_OVERRIDE_RTADV) == -1)
-- syslog(LOG_ERR, "%s: del_if_nd6_flag: %m",
-- ctx->ra_restore[ctx->ra_restore_len - 1]);
--#endif
-- }
--#endif
-- free(ctx->ra_restore[ctx->ra_restore_len - 1]);
-- }
-- free(ctx->ra_restore);
-- ctx->ra_restore = NULL;
--
-- if (ctx->ra_kernel_set) {
-- syslog(LOG_DEBUG, "restoring kernel IPv6 RA support");
-- if (set_inet6_sysctl(IPV6CTL_ACCEPT_RTADV, 1) == -1)
-- syslog(LOG_ERR, "IPV6CTL_ACCEPT_RTADV: %m");
-- }
--}
--
- static int
- if_raflush(void)
- {
-@@ -1085,10 +1046,6 @@
- #ifdef ND6_IFF_OVERRIDE_RTADV
- int override;
- #endif
--#ifdef ND6_IFF_ACCEPT_RTADV
-- size_t i;
-- char *p, **nrest;
--#endif
-
- #ifdef ND6_IFF_IFDISABLED
- if (del_if_nd6_flag(ifname, ND6_IFF_IFDISABLED) == -1) {
-@@ -1166,7 +1123,7 @@
- return ra;
- }
- #ifdef ND6_IFF_OVERRIDE_RTADV
-- if (override == 0 && ctx->ra_kernel_set == 0 &&
-+ if (override == 0 &&
- set_if_nd6_flag(ifname, ND6_IFF_OVERRIDE_RTADV)
- == -1)
- {
-@@ -1177,25 +1134,6 @@
- return ra;
- }
- #endif
-- for (i = 0; i < ctx->ra_restore_len; i++)
-- if (strcmp(ctx->ra_restore[i], ifname) == 0)
-- break;
-- if (i == ctx->ra_restore_len) {
-- p = strdup(ifname);
-- if (p == NULL) {
-- syslog(LOG_ERR, "%s: %m", __func__);
-- return 0;
-- }
-- nrest = realloc(ctx->ra_restore,
-- (ctx->ra_restore_len + 1) * sizeof(char *));
-- if (nrest == NULL) {
-- syslog(LOG_ERR, "%s: %m", __func__);
-- free(p);
-- return 0;
-- }
-- ctx->ra_restore = nrest;
-- ctx->ra_restore[ctx->ra_restore_len++] = p;
-- }
- return 0;
- }
- return ra;
-@@ -1217,7 +1155,6 @@
- return ra;
- }
- ra = 0;
-- ctx->ra_kernel_set = 1;
-
- /* Flush the kernel knowledge of advertised routers
- * and prefixes so the kernel does not expire prefixes
-diff -urN dhcpcd-6.4.0.org/if.c dhcpcd-6.4.0/if.c
---- dhcpcd-6.4.0.org/if.c 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/if.c 2014-07-05 21:47:22.000000000 +0200
-@@ -133,7 +133,7 @@
- }
-
- int
--if_up(struct interface *ifp)
-+if_setflag(struct interface *ifp, short flag)
- {
- struct ifreq ifr;
- int s, r;
-@@ -152,10 +152,10 @@
- #endif
- r = -1;
- if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) {
-- if ((ifr.ifr_flags & IFF_UP))
-+ if (flag == 0 || ifr.ifr_flags & flag)
- r = 0;
- else {
-- ifr.ifr_flags |= IFF_UP;
-+ ifr.ifr_flags |= flag;
- if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
- r = 0;
- }
-@@ -295,6 +295,7 @@
- ifp->ctx = ctx;
- strlcpy(ifp->name, p, sizeof(ifp->name));
- ifp->flags = ifa->ifa_flags;
-+ ifp->carrier = if_carrier(ifp);
-
- sdl_type = 0;
- /* Don't allow loopback unless explicit */
-diff -urN dhcpcd-6.4.0.org/if.h dhcpcd-6.4.0/if.h
---- dhcpcd-6.4.0.org/if.h 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/if.h 2014-07-05 21:47:22.000000000 +0200
-@@ -90,7 +90,8 @@
- #define RAW_EOF 1 << 0
- #define RAW_PARTIALCSUM 2 << 0
-
--int if_up(struct interface *ifp);
-+int if_setflag(struct interface *ifp, short flag);
-+#define if_up(ifp) if_setflag((ifp), IFF_UP)
- struct if_head *if_discover(struct dhcpcd_ctx *, int, char * const *);
- struct interface *if_find(struct dhcpcd_ctx *, const char *);
- void if_free(struct interface *);
-@@ -131,7 +132,6 @@
-
- #ifdef INET6
- int if_checkipv6(struct dhcpcd_ctx *ctx, const char *, int);
--void if_rarestore(struct dhcpcd_ctx *);
- int if_nd6reachable(const char *ifname, struct in6_addr *addr);
-
- int if_address6(const struct ipv6_addr *, int);
-@@ -145,7 +145,6 @@
- #define if_delroute6(rt) if_route6(rt, -1)
- #else
- #define if_checkipv6(a, b, c) (-1)
--#define if_rarestore(a)
- #endif
-
- int if_machinearch(char *, size_t);
-diff -urN dhcpcd-6.4.0.org/if-linux.c dhcpcd-6.4.0/if-linux.c
---- dhcpcd-6.4.0.org/if-linux.c 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/if-linux.c 2014-07-05 21:47:22.000000000 +0200
-@@ -1223,33 +1223,11 @@
-
- static const char *prefix = "/proc/sys/net/ipv6/conf";
-
--void
--if_rarestore(struct dhcpcd_ctx *ctx)
--{
-- char path[256];
--
-- for (; ctx->ra_restore_len > 0; ctx->ra_restore_len--) {
-- if (!(ctx->options & DHCPCD_FORKED)) {
-- syslog(LOG_DEBUG,
-- "%s: restoring kernel IPv6 RA support",
-- ctx->ra_restore[ctx->ra_restore_len - 1]);
-- snprintf(path, sizeof(path), "%s/%s/accept_ra",
-- prefix, ctx->ra_restore[ctx->ra_restore_len - 1]);
-- if (write_path(path, "1") == -1 && errno != ENOENT)
-- syslog(LOG_ERR, "write_path: %s: %m", path);
-- }
-- free(ctx->ra_restore[ctx->ra_restore_len - 1]);
-- }
-- free(ctx->ra_restore);
-- ctx->ra_restore = NULL;
--}
--
- int
--if_checkipv6(struct dhcpcd_ctx *ctx, const char *ifname, int own)
-+if_checkipv6(__unused struct dhcpcd_ctx *ctx, const char *ifname, int own)
- {
- int ra;
-- size_t i;
-- char path[256], *p, **nrest;
-+ char path[256];
-
- if (ifname == NULL)
- ifname = "all";
-@@ -1283,25 +1261,6 @@
- syslog(LOG_ERR, "write_path: %s: %m", path);
- return ra;
- }
-- for (i = 0; i < ctx->ra_restore_len; i++)
-- if (strcmp(ctx->ra_restore[i], ifname) == 0)
-- break;
-- if (i == ctx->ra_restore_len) {
-- p = strdup(ifname);
-- if (p == NULL) {
-- syslog(LOG_ERR, "%s: %m", __func__);
-- return 0;
-- }
-- nrest = realloc(ctx->ra_restore,
-- (ctx->ra_restore_len + 1) * sizeof(char *));
-- if (nrest == NULL) {
-- syslog(LOG_ERR, "%s: %m", __func__);
-- free(p);
-- return 0;
-- }
-- ctx->ra_restore = nrest;
-- ctx->ra_restore[ctx->ra_restore_len++] = p;
-- }
- return 0;
- }
-
-diff -urN dhcpcd-6.4.0.org/if-options.c dhcpcd-6.4.0/if-options.c
---- dhcpcd-6.4.0.org/if-options.c 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/if-options.c 2014-07-05 21:47:22.000000000 +0200
-@@ -93,6 +93,8 @@
- #define O_CONTROLGRP O_BASE + 34
- #define O_SLAAC O_BASE + 35
- #define O_GATEWAY O_BASE + 36
-+#define O_NOPFXDLG O_BASE + 37
-+#define O_PFXDLGONLY O_BASE + 38
-
- const struct option cf_options[] = {
- {"background", no_argument, NULL, 'b'},
-@@ -179,6 +181,8 @@
- {"controlgroup", required_argument, NULL, O_CONTROLGRP},
- {"slaac", required_argument, NULL, O_SLAAC},
- {"gateway", no_argument, NULL, O_GATEWAY},
-+ {"nopfxdlg", no_argument, NULL, O_NOPFXDLG},
-+ {"pfxdlgonly", no_argument, NULL, O_PFXDLGONLY},
- {NULL, 0, NULL, '\0'}
- };
-
-@@ -518,7 +522,9 @@
-
- static const char *
- set_option_space(struct dhcpcd_ctx *ctx,
-- const char *arg, const struct dhcp_opt **d, size_t *dl,
-+ const char *arg,
-+ const struct dhcp_opt **d, size_t *dl,
-+ const struct dhcp_opt **od, size_t *odl,
- struct if_options *ifo,
- uint8_t *request[], uint8_t *require[], uint8_t *no[])
- {
-@@ -527,6 +533,8 @@
- if (strncmp(arg, "dhcp6_", strlen("dhcp6_")) == 0) {
- *d = ctx->dhcp6_opts;
- *dl = ctx->dhcp6_opts_len;
-+ *od = ifo->dhcp6_override;
-+ *odl = ifo->dhcp6_override_len;
- *request = ifo->requestmask6;
- *require = ifo->requiremask6;
- *no = ifo->nomask6;
-@@ -537,9 +545,13 @@
- #ifdef INET
- *d = ctx->dhcp_opts;
- *dl = ctx->dhcp_opts_len;
-+ *od = ifo->dhcp_override;
-+ *odl = ifo->dhcp_override_len;
- #else
- *d = NULL;
- *dl = 0;
-+ *od = NULL;
-+ *odl = 0;
- #endif
- *request = ifo->requestmask;
- *require = ifo->requiremask;
-@@ -630,10 +642,10 @@
- struct in_addr addr, addr2;
- in_addr_t *naddr;
- struct rt *rt;
-- const struct dhcp_opt *d;
-+ const struct dhcp_opt *d, *od;
- uint8_t *request, *require, *no;
- struct dhcp_opt **dop, *ndop;
-- size_t *dop_len, dl;
-+ size_t *dop_len, dl, odl;
- struct vivco *vivco;
- struct token *token;
- struct group *grp;
-@@ -733,10 +745,10 @@
- }
- break;
- case 'o':
-- arg = set_option_space(ctx, arg, &d, &dl, ifo,
-+ arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
- &request, &require, &no);
-- if (make_option_mask(d, dl, request, arg, 1) != 0 ||
-- make_option_mask(d, dl, no, arg, -1) != 0)
-+ if (make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
-+ make_option_mask(d, dl, od, odl, no, arg, -1) != 0)
- {
- syslog(LOG_ERR, "unknown option `%s'", arg);
- return -1;
-@@ -952,22 +964,22 @@
- ifo->options |= DHCPCD_MASTER;
- break;
- case 'O':
-- arg = set_option_space(ctx, arg, &d, &dl, ifo,
-+ arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
- &request, &require, &no);
-- if (make_option_mask(d, dl, request, arg, -1) != 0 ||
-- make_option_mask(d, dl, require, arg, -1) != 0 ||
-- make_option_mask(d, dl, no, arg, 1) != 0)
-+ if (make_option_mask(d, dl, od, odl, request, arg, -1) != 0 ||
-+ make_option_mask(d, dl, od, odl, require, arg, -1) != 0 ||
-+ make_option_mask(d, dl, od, odl, no, arg, 1) != 0)
- {
- syslog(LOG_ERR, "unknown option `%s'", arg);
- return -1;
- }
- break;
- case 'Q':
-- arg = set_option_space(ctx, arg, &d, &dl, ifo,
-+ arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
- &request, &require, &no);
-- if (make_option_mask(d, dl, require, arg, 1) != 0 ||
-- make_option_mask(d, dl, request, arg, 1) != 0 ||
-- make_option_mask(d, dl, no, arg, -1) != 0)
-+ if (make_option_mask(d, dl, od, odl, require, arg, 1) != 0 ||
-+ make_option_mask(d, dl, od, odl, request, arg, 1) != 0 ||
-+ make_option_mask(d, dl, od, odl, no, arg, -1) != 0)
- {
- syslog(LOG_ERR, "unknown option `%s'", arg);
- return -1;
-@@ -1156,8 +1168,11 @@
- }
- break;
- case O_DESTINATION:
-- if (make_option_mask(ctx->dhcp_opts, ctx->dhcp_opts_len,
-- ifo->dstmask, arg, 2) != 0) {
-+ arg = set_option_space(ctx, arg, &d, &dl, &od, &odl, ifo,
-+ &request, &require, &no);
-+ if (make_option_mask(d, dl, od, odl,
-+ ifo->dstmask, arg, 2) != 0)
-+ {
- if (errno == EINVAL)
- syslog(LOG_ERR, "option `%s' does not take"
- " an IPv4 address", arg);
-@@ -1220,35 +1235,40 @@
- }
- i = D6_OPTION_IA_PD;
- }
-- if (arg != NULL && ifname == NULL) {
-+ if (ifname == NULL && arg) {
- syslog(LOG_ERR,
- "IA with IAID must belong in an interface block");
- return -1;
- }
- ifo->options |= DHCPCD_IA_FORCED;
-- if (ifo->ia_type != 0 && ifo->ia_type != i) {
-- syslog(LOG_ERR, "cannot specify a different IA type");
-- return -1;
-- }
-- ifo->ia_type = (uint16_t)i;
-- if (arg == NULL)
-- break;
- fp = strwhite(arg);
-- if (fp)
-+ if (fp) {
- *fp++ = '\0';
-- if (parse_iaid(iaid, arg, sizeof(iaid)) == -1)
-- return -1;
-+ fp = strskipwhite(fp);
-+ }
-+ if (arg) {
-+ p = strchr(arg, '/');
-+ if (p)
-+ *p++ = '\0';
-+ if (parse_iaid(iaid, arg, sizeof(iaid)) == -1)
-+ return -1;
-+ }
- ia = NULL;
- for (sl = 0; sl < ifo->ia_len; sl++) {
-- if (ifo->ia[sl].iaid[0] == iaid[0] &&
-+ if ((arg == NULL && !ifo->ia[sl].iaid_set) ||
-+ (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])
-+ ifo->ia[sl].iaid[3] == iaid[3]))
- {
- ia = &ifo->ia[sl];
- break;
- }
- }
-+ if (ia && ia->ia_type != (uint16_t)i) {
-+ syslog(LOG_ERR, "Cannot mix IA for the same IAID");
-+ break;
-+ }
- if (ia == NULL) {
- ia = realloc(ifo->ia,
- sizeof(*ifo->ia) * (ifo->ia_len + 1));
-@@ -1258,14 +1278,47 @@
- }
- 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->ia_type = (uint16_t)i;
-+ if (arg) {
-+ ia->iaid[0] = iaid[0];
-+ ia->iaid[1] = iaid[1];
-+ ia->iaid[2] = iaid[2];
-+ ia->iaid[3] = iaid[3];
-+ ia->iaid_set = 1;
-+ } else
-+ ia->iaid_set = 0;
-+ if (!ia->iaid_set ||
-+ p == NULL ||
-+ ia->ia_type == D6_OPTION_IA_TA)
-+ {
-+ 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 && ia->ia_type == D6_OPTION_IA_PD) {
-+ 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)
-+ if (ia->ia_type != D6_OPTION_IA_PD)
- break;
- for (p = fp; p; p = fp) {
- fp = strwhite(p);
-@@ -1284,12 +1337,6 @@
- np = strchr(p, '/');
- if (np)
- *np++ = '\0';
-- if (strcmp(ifname, p) == 0) {
-- syslog(LOG_ERR,
-- "%s: cannot assign IA_PD to itself",
-- ifname);
-- goto err_sla;
-- }
- if (strlcpy(sla->ifname, p,
- sizeof(sla->ifname)) >= sizeof(sla->ifname))
- {
-@@ -1853,6 +1900,12 @@
- else
- ifo->options &= ~DHCPCD_SLAACPRIVATE;
- break;
-+ case O_NOPFXDLG:
-+ ifo->options |= DHCPCD_NOPFXDLG;
-+ break;
-+ case O_PFXDLGONLY:
-+ ifo->options |= DHCPCD_PFXDLGONLY;
-+ break;
- default:
- return 0;
- }
-@@ -2124,6 +2177,10 @@
- skip = 1;
- continue;
- }
-+ /* Skip arping if we have selected a profile but not parsing
-+ * one. */
-+ if (profile && !have_profile && strcmp(option, "arping") == 0)
-+ continue;
- if (skip)
- continue;
- parse_config_line(ctx, ifname, ifo, option, line, &ldop, &edop);
-diff -urN dhcpcd-6.4.0.org/if-options.h dhcpcd-6.4.0/if-options.h
---- dhcpcd-6.4.0.org/if-options.h 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/if-options.h 2014-07-05 21:47:22.000000000 +0200
-@@ -28,6 +28,7 @@
- #ifndef IF_OPTIONS_H
- #define IF_OPTIONS_H
-
-+#include <sys/param.h>
- #include <sys/socket.h>
- #include <net/if.h>
- #include <netinet/in.h>
-@@ -102,6 +103,8 @@
- #define DHCPCD_IAID (1ULL << 48)
- #define DHCPCD_DHCP (1ULL << 49)
- #define DHCPCD_DHCP6 (1ULL << 50)
-+#define DHCPCD_NOPFXDLG (1ULL << 51)
-+#define DHCPCD_PFXDLGONLY (1ULL << 52)
-
- extern const struct option cf_options[];
-
-@@ -115,6 +118,10 @@
- struct if_ia {
- uint8_t iaid[4];
- #ifdef INET6
-+ uint16_t ia_type;
-+ uint8_t iaid_set;
-+ struct in6_addr addr;
-+ uint8_t prefix_len;
- size_t sla_len;
- struct if_sla *sla;
- #endif
-@@ -128,13 +135,13 @@
- struct if_options {
- uint8_t iaid[4];
- int metric;
-- uint8_t requestmask[256 / 8];
-- uint8_t requiremask[256 / 8];
-- uint8_t nomask[256 / 8];
-- uint8_t requestmask6[(UINT16_MAX + 1) / 8];
-- uint8_t requiremask6[(UINT16_MAX + 1) / 8];
-- uint8_t nomask6[(UINT16_MAX + 1) / 8];
-- uint8_t dstmask[256 / 8];
-+ uint8_t requestmask[256 / NBBY];
-+ uint8_t requiremask[256 / NBBY];
-+ uint8_t nomask[256 / NBBY];
-+ uint8_t requestmask6[(UINT16_MAX + 1) / NBBY];
-+ uint8_t requiremask6[(UINT16_MAX + 1) / NBBY];
-+ uint8_t nomask6[(UINT16_MAX + 1) / NBBY];
-+ uint8_t dstmask[256 / NBBY];
- uint32_t leasetime;
- time_t timeout;
- time_t reboot;
-@@ -163,7 +170,6 @@
- in_addr_t *arping;
- char *fallback;
-
-- uint16_t ia_type;
- struct if_ia *ia;
- size_t ia_len;
-
-diff -urN dhcpcd-6.4.0.org/ipv4.c dhcpcd-6.4.0/ipv4.c
---- dhcpcd-6.4.0.org/ipv4.c 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/ipv4.c 2014-07-05 21:47:22.000000000 +0200
-@@ -82,13 +82,13 @@
- errno = EINVAL;
- return -1;
- }
-- ocets = (cidr + 7) / 8;
-+ ocets = (cidr + 7) / NBBY;
-
- addr->s_addr = 0;
- if (ocets > 0) {
- memset(&addr->s_addr, 255, (size_t)ocets - 1);
- memset((unsigned char *)&addr->s_addr + (ocets - 1),
-- (256 - (1 << (32 - cidr) % 8)), 1);
-+ (256 - (1 << (32 - cidr) % NBBY)), 1);
- }
-
- return 0;
-diff -urN dhcpcd-6.4.0.org/ipv6.c dhcpcd-6.4.0/ipv6.c
---- dhcpcd-6.4.0.org/ipv6.c 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/ipv6.c 2014-07-05 21:47:22.000000000 +0200
-@@ -652,7 +652,6 @@
- i = 0;
- TAILQ_FOREACH_SAFE(ap, addrs, next, apn) {
- if (ap->prefix_vltime == 0) {
-- TAILQ_REMOVE(addrs, ap, next);
- if (ap->flags & IPV6_AF_ADDED) {
- syslog(LOG_INFO, "%s: deleting address %s",
- ap->iface->name, ap->saddr);
-@@ -664,7 +663,12 @@
- }
- eloop_q_timeout_delete(ap->iface->ctx->eloop,
- 0, NULL, ap);
-- free(ap);
-+ if (ap->flags & IPV6_AF_REQUEST) {
-+ ap->flags &= ~IPV6_AF_ADDED;
-+ } else {
-+ TAILQ_REMOVE(addrs, ap, next);
-+ free(ap);
-+ }
- } else if (!IN6_IS_ADDR_UNSPECIFIED(&ap->addr)) {
- if (ap->flags & IPV6_AF_NEW)
- i++;
-diff -urN dhcpcd-6.4.0.org/ipv6.h dhcpcd-6.4.0/ipv6.h
---- dhcpcd-6.4.0.org/ipv6.h 2014-06-14 22:13:12.000000000 +0200
-+++ dhcpcd-6.4.0/ipv6.h 2014-07-05 21:47:22.000000000 +0200
-@@ -90,7 +90,10 @@
- short flags;
- char saddr[INET6_ADDRSTRLEN];
- uint8_t iaid[4];
-+ uint16_t ia_type;
- struct interface *delegating_iface;
-+ uint8_t prefix_exclude_len;
-+ struct in6_addr prefix_exclude;
-
- void (*dadcallback)(void *);
- int dadcounter;
-@@ -109,7 +112,8 @@
- #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;
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/dhcpcd.git/commitdiff/4269699a1aad65a58e2fce90ee2e17a9f9cda6cf
More information about the pld-cvs-commit
mailing list