summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/config.c9
-rw-r--r--src/netlink.c11
-rw-r--r--src/odhcpd.h2
-rw-r--r--src/router.c6
4 files changed, 27 insertions, 1 deletions
diff --git a/src/config.c b/src/config.c
index 30da879..ee7219f 100644
--- a/src/config.c
+++ b/src/config.c
@@ -594,6 +594,15 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
if (len > 0)
iface->addr6_len = len;
+ for (size_t i = 0; i < iface->addr6_len; i++) {
+ struct odhcpd_ipaddr *addr = &iface->addr6[i];
+
+ if (!addr->tentative) {
+ iface->have_link_local = true;
+ break;
+ }
+ }
+
len = netlink_get_interface_addrs(iface->ifindex,
false, &iface->addr4);
if (len > 0)
diff --git a/src/netlink.c b/src/netlink.c
index 4a352a6..0a2da03 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -386,7 +386,7 @@ static int handle_rtm_addr(struct nlmsghdr *hdr, bool add)
nla_memcpy(&event_info.addr, nla[IFA_ADDRESS], sizeof(event_info.addr));
- if (IN6_IS_ADDR_LINKLOCAL(&event_info.addr) || IN6_IS_ADDR_MULTICAST(&event_info.addr))
+ if (IN6_IS_ADDR_MULTICAST(&event_info.addr))
return NL_SKIP;
inet_ntop(AF_INET6, &event_info.addr, buf, sizeof(buf));
@@ -395,6 +395,11 @@ static int handle_rtm_addr(struct nlmsghdr *hdr, bool add)
if (iface->ifindex != (int)ifa->ifa_index)
continue;
+ if (add && IN6_IS_ADDR_LINKLOCAL(&event_info.addr)) {
+ iface->have_link_local = true;
+ return NL_SKIP;
+ }
+
syslog(LOG_DEBUG, "Netlink %s %s on %s", add ? "newaddr" : "deladdr",
buf, iface->name);
@@ -625,6 +630,10 @@ static int cb_addr_valid(struct nl_msg *msg, void *arg)
if (ifa->ifa_flags & IFA_F_DEPRECATED)
addrs[ctxt->ret].preferred = 0;
+ if (ifa->ifa_family == AF_INET6 &&
+ ifa->ifa_flags & IFA_F_TENTATIVE)
+ addrs[ctxt->ret].tentative = true;
+
ctxt->ret++;
*(ctxt->addrs) = addrs;
diff --git a/src/odhcpd.h b/src/odhcpd.h
index d829033..0550bc2 100644
--- a/src/odhcpd.h
+++ b/src/odhcpd.h
@@ -131,6 +131,7 @@ struct odhcpd_ipaddr {
struct {
uint8_t dprefix;
uint8_t invalid_advertisements;
+ bool tentative;
};
/* ipv4 only */
@@ -300,6 +301,7 @@ struct interface {
bool ra_useleasetime;
bool ra_dns;
bool no_dynamic_dhcp;
+ bool have_link_local;
uint8_t pio_filter_length;
struct in6_addr pio_filter_addr;
int default_router;
diff --git a/src/router.c b/src/router.c
index 7e66e3c..eca0bf7 100644
--- a/src/router.c
+++ b/src/router.c
@@ -621,6 +621,11 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr
msecs = calc_adv_interval(iface, minvalid, &maxival);
lifetime = calc_ra_lifetime(iface, maxival);
+ if (!iface->have_link_local) {
+ syslog(LOG_NOTICE, "Skip sending a RA on %s as no link local address is available", iface->name);
+ goto out;
+ }
+
if (default_route && valid_prefix) {
adv.h.nd_ra_router_lifetime = htons(lifetime < UINT16_MAX ? lifetime : UINT16_MAX);
} else {
@@ -782,6 +787,7 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr
if (odhcpd_send(iface->router_event.uloop.fd, &dest, iov, ARRAY_SIZE(iov), iface) > 0)
iface->ra_sent++;
+out:
free(pfxs);
free(routes);