From: Roy Marples Date: Wed, 15 Oct 2014 14:23:53 +0000 (+0000) Subject: Work better with unknown prefix length requirements in the configuration. X-Git-Tag: v6.5.1~21 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e69793ffc1a13a5bec11adbe3175400aeaf305fb;p=thirdparty%2Fdhcpcd.git Work better with unknown prefix length requirements in the configuration. --- diff --git a/dhcp6.c b/dhcp6.c index a5d3b19f..85a8b97f 100644 --- a/dhcp6.c +++ b/dhcp6.c @@ -353,14 +353,49 @@ dhcp6_findselfsla(struct interface *ifp, const uint8_t *iaid) return NULL; } + +#ifndef ffs32 +static int +ffs32(uint32_t n) +{ + int v; + + if (!n) + return 0; + + v = 1; + if ((n & 0x0000FFFFU) == 0) { + n >>= 16; + v += 16; + } + if ((n & 0x000000FFU) == 0) { + n >>= 8; + v += 8; + } + if ((n & 0x0000000FU) == 0) { + n >>= 4; + v += 4; + } + if ((n & 0x00000003U) == 0) { + n >>= 2; + v += 2; + } + if ((n & 0x00000001U) == 0) { + n >>= 1; + v += 1; + } + return v; +} +#endif + static int dhcp6_delegateaddr(struct in6_addr *addr, struct interface *ifp, - const struct ipv6_addr *prefix, const struct if_sla *sla) + const struct ipv6_addr *prefix, const struct if_sla *sla, struct if_ia *ia) { struct dhcp6_state *state; struct if_sla asla; - char iabuf[INET6_ADDRSTRLEN]; - const char *ia; + char sabuf[INET6_ADDRSTRLEN]; + const char *sa; state = D6_STATE(ifp); if (state == NULL) { @@ -377,18 +412,34 @@ dhcp6_delegateaddr(struct in6_addr *addr, struct interface *ifp, } 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; + asla.prefix_len = 0; + sla = &asla; + + if (ia->sla_max == 0) { } - bits = ffs((int)idx); + } else if (sla->prefix_len == 0) { + asla.sla = sla->sla; + asla.prefix_len = 0; + sla = &asla; + } + if (sla->prefix_len == 0) { + uint32_t sla_max; + int bits; + + if (ia->sla_max == 0) { + const struct interface *ifi; + + sla_max = 0; + TAILQ_FOREACH(ifi, ifp->ctx->ifaces, next) { + if (ifi != ifp && ifi->index > sla_max) + sla_max = ifi->index; + } + } else + sla_max = ia->sla_max; + + bits = ffs32(sla_max); + if (prefix->prefix_len + bits > UINT8_MAX) asla.prefix_len = UINT8_MAX; else { @@ -402,16 +453,22 @@ dhcp6_delegateaddr(struct in6_addr *addr, struct interface *ifp, asla.prefix_len = ROUNDUP8(asla.prefix_len); } - sla = &asla; + +#define BIT(n) (1l << (n)) +#define BIT_MASK(len) (BIT(len) - 1) + if (ia->sla_max == 0) + /* Work out the real sla_max from our bits used */ + ia->sla_max = BIT_MASK(asla.prefix_len - + prefix->prefix_len); } if (ipv6_userprefix(&prefix->prefix, prefix->prefix_len, sla->sla, addr, sla->prefix_len) == -1) { - ia = inet_ntop(AF_INET6, &prefix->prefix, - iabuf, sizeof(iabuf)); + sa = inet_ntop(AF_INET6, &prefix->prefix, + sabuf, sizeof(sabuf)); syslog(LOG_ERR, "%s: invalid prefix %s/%d + %d/%d: %m", - ifp->name, ia, prefix->prefix_len, + ifp->name, sa, prefix->prefix_len, sla->sla, sla->prefix_len); return -1; } @@ -419,10 +476,10 @@ dhcp6_delegateaddr(struct in6_addr *addr, struct interface *ifp, if (prefix->prefix_exclude_len && IN6_ARE_ADDR_EQUAL(addr, &prefix->prefix_exclude)) { - ia = inet_ntop(AF_INET6, &prefix->prefix_exclude, - iabuf, sizeof(iabuf)); + sa = inet_ntop(AF_INET6, &prefix->prefix_exclude, + sabuf, sizeof(sabuf)); syslog(LOG_ERR, "%s: cannot delegate excluded prefix %s/%d", - ifp->name, ia, prefix->prefix_exclude_len); + ifp->name, sa, prefix->prefix_exclude_len); return -1; } @@ -2174,13 +2231,13 @@ dhcp6_startinit(struct interface *ifp) static struct ipv6_addr * dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix, - const struct if_sla *sla, struct interface *ifs) + const struct if_sla *sla, struct if_ia *ia, struct interface *ifs) { struct dhcp6_state *state; struct in6_addr addr; struct ipv6_addr *a, *ap, *apn; - char iabuf[INET6_ADDRSTRLEN]; - const char *ia; + char sabuf[INET6_ADDRSTRLEN]; + const char *sa; int pfxlen; /* RFC6603 Section 4.2 */ @@ -2196,7 +2253,8 @@ dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix, } pfxlen = prefix->prefix_exclude_len; memcpy(&addr, &prefix->prefix_exclude, sizeof(addr)); - } else if ((pfxlen = dhcp6_delegateaddr(&addr, ifp, prefix, sla)) == -1) + } else if ((pfxlen = dhcp6_delegateaddr(&addr, ifp, prefix, + sla, ia)) == -1) return NULL; @@ -2232,8 +2290,8 @@ dhcp6_ifdelegateaddr(struct interface *ifp, struct ipv6_addr *prefix, } } - ia = inet_ntop(AF_INET6, &a->addr, iabuf, sizeof(iabuf)); - snprintf(a->saddr, sizeof(a->saddr), "%s/%d", ia, a->prefix_len); + sa = inet_ntop(AF_INET6, &a->addr, sabuf, sizeof(sabuf)); + snprintf(a->saddr, sizeof(a->saddr), "%s/%d", sa, a->prefix_len); TAILQ_INSERT_TAIL(&state->addrs, a, next); return a; } @@ -2345,7 +2403,7 @@ dhcp6_delegate_prefix(struct interface *ifp) break; } if (dhcp6_ifdelegateaddr(ifd, ap, - NULL, ifp)) + NULL, ia, ifp)) k++; } for (j = 0; j < ia->sla_len; j++) { @@ -2364,7 +2422,7 @@ dhcp6_delegate_prefix(struct interface *ifp) break; } if (dhcp6_ifdelegateaddr(ifd, ap, - sla, ifp)) + sla, ia, ifp)) k++; } if (carrier_warned ||abrt) @@ -2428,7 +2486,7 @@ dhcp6_find_delegates(struct interface *ifp) return 1; } if (dhcp6_ifdelegateaddr(ifp, ap, - sla, ifd)) + sla, ia, ifd)) k++; } } diff --git a/if-options.c b/if-options.c index 74c09168..de7eeb29 100644 --- a/if-options.c +++ b/if-options.c @@ -1313,6 +1313,7 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, ia->prefix_len = (uint8_t)i; } } + ia->sla_max = 0; ia->sla_len = 0; ia->sla = NULL; } @@ -1372,27 +1373,34 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, goto err_sla; sla->prefix_len = (uint8_t)i; } else - sla->prefix_len = 64; + sla->prefix_len = 0; } else { sla->sla_set = 0; - /* Sanity - check there are no more - * unspecified SLA's */ - for (sl = 0; sl < ia->sla_len - 1; sl++) { - slap = &ia->sla[sl]; - if (slap->sla_set == 0 && - strcmp(slap->ifname, sla->ifname) - == 0) - { - syslog(LOG_WARNING, - "%s: cannot specify the " - "same interface twice with " - "an automatic SLA", - sla->ifname); - ia->sla_len--; - break; - } + sla->prefix_len = 0; + } + /* Sanity check */ + for (sl = 0; sl < ia->sla_len - 1; sl++) { + slap = &ia->sla[sl]; + if (slap->sla_set && sla->sla_set == 0) { + syslog(LOG_WARNING, + "%s: cannot mix automatic " + "and fixed SLA", + sla->ifname); + goto err_sla; + } + if (sla->sla_set == 0 && + strcmp(slap->ifname, sla->ifname) == 0) + { + syslog(LOG_WARNING, + "%s: cannot specify the " + "same interface twice with " + "an automatic SLA", + sla->ifname); + goto err_sla; } } + if (sla->sla_set && sla->sla > ia->sla_max) + ia->sla_max = sla->sla; } break; err_sla: diff --git a/if-options.h b/if-options.h index a73f7851..82e3e95a 100644 --- a/if-options.h +++ b/if-options.h @@ -123,6 +123,7 @@ struct if_ia { uint8_t iaid_set; struct in6_addr addr; uint8_t prefix_len; + uint32_t sla_max; size_t sla_len; struct if_sla *sla; #endif