diff options
-rw-r--r-- | src/config.c | 9 | ||||
-rw-r--r-- | src/netlink.c | 11 | ||||
-rw-r--r-- | src/odhcpd.h | 2 | ||||
-rw-r--r-- | src/router.c | 6 |
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); |