#define DHCPCD_ARP (1ULL << 0)
#define DHCPCD_RELEASE (1ULL << 1)
-// unused (1ULL << 2)
+#define DHCPCD_RTBUILD (1ULL << 2)
#define DHCPCD_GATEWAY (1ULL << 3)
#define DHCPCD_STATIC (1ULL << 4)
#define DHCPCD_DEBUG (1ULL << 5)
return state;
}
+struct ipv6_addr *
+ipv6_ifanyglobal(struct interface *ifp)
+{
+ struct ipv6_state *state;
+ struct ipv6_addr *ia;
+
+ if (ifp->carrier == LINK_DOWN)
+ return NULL;
+
+ state = IPV6_STATE(ifp);
+ if (state == NULL)
+ return NULL;
+
+ TAILQ_FOREACH(ia, &state->addrs, next) {
+ if (IN6_IS_ADDR_LINKLOCAL(&ia->addr))
+ continue;
+ if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
+ break;
+ }
+ return ia;
+}
+
void
ipv6_handleifa(struct dhcpcd_ctx *ctx,
int cmd, struct if_head *ifs, const char *ifname,
struct ipv6_state *state;
struct ipv6_addr *ia;
struct ll_callback *cb;
+ bool anyglobal;
#if 0
char dbuf[INET6_ADDRSTRLEN];
return;
if ((state = ipv6_getstate(ifp)) == NULL)
return;
+ anyglobal = ipv6_ifanyglobal(ifp) != NULL;
TAILQ_FOREACH(ia, &state->addrs, next) {
if (IN6_ARE_ADDR_EQUAL(&ia->addr, addr))
if (ia == NULL)
return;
+ ctx->options &= ~DHCPCD_RTBUILD;
ipv6nd_handleifa(cmd, ia, pid);
#ifdef DHCP6
dhcp6_handleifa(cmd, ia, pid);
ipv6_freeaddr(ia);
else if (!(ia->addr_flags & IN6_IFF_NOTUSEABLE))
ia->flags |= IPV6_AF_DADCOMPLETED;
+
+ /* If we've not already called rt_build via the IPv6ND
+ * or DHCP6 handlers and the existance of any useable
+ * global address on the interface has changed,
+ * call rt_build to add/remove the default route. */
+ if (!(ctx->options & DHCPCD_RTBUILD) &&
+ (ipv6_ifanyglobal(ifp) != NULL) != anyglobal)
+ rt_build(ctx, AF_INET6);
}
int
}
if (rap->lifetime == 0)
continue;
+ if (ipv6_ifanyglobal(rap->iface) == NULL)
+ continue;
rt = inet6_makerouter(rap);
if (rt == NULL)
continue;
struct ipv6_addr *ipv6_iffindaddr(struct interface *,
const struct in6_addr *, int);
int ipv6_hasaddr(const struct interface *);
+struct ipv6_addr *ipv6_ifanyglobal(struct interface *);
int ipv6_findaddrmatch(const struct ipv6_addr *, const struct in6_addr *,
unsigned int);
struct ipv6_addr *ipv6_findaddr(struct dhcpcd_ctx *,
struct in6_addr pi_prefix;
struct ipv6_addr *ap;
struct dhcp_opt *dho;
- bool new_rap, new_data;
+ bool new_rap, new_data, has_address;
uint32_t old_lifetime;
__printflike(1, 2) void (*logfunc)(const char *, ...);
#ifdef IPV6_MANAGETEMPADDR
* routers like to decrease the advertised valid and preferred times
* in accordance with the own prefix times which would result in too
* much needless log spam. */
- logfunc = new_rap || !rap->isreachable ? loginfox : logdebugx,
+ logfunc = new_data || !rap->isreachable ? loginfox : logdebugx,
logfunc("%s: Router Advertisement from %s", ifp->name, rap->sfrom);
clock_gettime(CLOCK_MONOTONIC, &rap->acquired);
rap->expired = false;
rap->hasdns = false;
rap->isreachable = true;
+ has_address = false;
#ifdef IPV6_AF_TEMPORARY
ipv6_markaddrsstale(ifp, IPV6_AF_TEMPORARY);
ntohl(pi.nd_opt_pi_valid_time);
ap->prefix_pltime =
ntohl(pi.nd_opt_pi_preferred_time);
+ if (ap->prefix_vltime != 0 &&
+ ap->flags & IPV6_AF_AUTOCONF)
+ has_address = true;
#ifdef IPV6_MANAGETEMPADDR
/* RFC4941 Section 3.3.3 */
}
}
+ if (new_data && !has_address && rap->lifetime && !ipv6_ifanyglobal(ifp))
+ logwarnx("%s: no global addresses for default route",
+ ifp->name);
+
if (new_rap)
add_router(ifp->ctx, rap);
ipv6nd_expirera(ifp);
}
-int
-ipv6nd_hasra(const struct interface *ifp)
+bool
+ipv6nd_hasralifetime(const struct interface *ifp, bool lifetime)
{
const struct ra *rap;
if (ifp->ctx->ra_routers) {
TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next)
- if (rap->iface == ifp && !rap->expired)
- return 1;
+ if (rap->iface == ifp && !rap->expired &&
+ (!lifetime ||rap->lifetime))
+ return true;
}
- return 0;
+ return false;
}
-int
+bool
ipv6nd_hasradhcp(const struct interface *ifp)
{
const struct ra *rap;
TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
if (rap->iface == ifp &&
!rap->expired &&
- (rap->flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)))
- return 1;
+ (rap->flags &(ND_RA_FLAG_MANAGED|ND_RA_FLAG_OTHER)))
+ return true;
}
}
- return 0;
+ return false;
}
static const uint8_t *
const struct in6_addr *, unsigned int);
ssize_t ipv6nd_free(struct interface *);
void ipv6nd_expirera(void *arg);
-int ipv6nd_hasra(const struct interface *);
-int ipv6nd_hasradhcp(const struct interface *);
+bool ipv6nd_hasralifetime(const struct interface *, bool);
+#define ipv6nd_hasra(i) ipv6nd_hasralifetime((i), false)
+bool ipv6nd_hasradhcp(const struct interface *);
void ipv6nd_handleifa(int, struct ipv6_addr *, pid_t);
int ipv6nd_dadcompleted(const struct interface *);
void ipv6nd_advertise(struct ipv6_addr *);
#include "common.h"
#include "dhcpcd.h"
#include "if.h"
+#include "if-options.h"
#include "ipv4.h"
#include "ipv4ll.h"
#include "ipv6.h"
rb_tree_init(&kroutes, &rt_compare_os_ops);
if_initrt(ctx, &kroutes, af);
ctx->rt_order = 0;
+ ctx->options |= DHCPCD_RTBUILD;
switch (af) {
#ifdef INET