- time_t now = time(NULL);
-
- struct ndp_neighbor *n = find_neighbor(&req->nd_ns_target, false);
- if (n && (n->iface || abs(n->timeout - now) < 5)) {
- syslog(LOG_DEBUG, "%s is on %s", ipbuf,
- (n->iface) ? n->iface->ifname : "<pending>");
- if (!n->iface || n->iface == iface)
- return;
-
- // Found on other interface, answer with advertisement
- struct {
- struct nd_neighbor_advert body;
- struct nd_opt_hdr opt_ll_hdr;
- uint8_t mac[6];
- } advert = {
- .body = {
- .nd_na_hdr = {ND_NEIGHBOR_ADVERT,
- 0, 0, {{0}}},
- .nd_na_target = req->nd_ns_target,
- },
- .opt_ll_hdr = {ND_OPT_TARGET_LINKADDR, 1},
- };
-
- memcpy(advert.mac, mac, sizeof(advert.mac));
- advert.body.nd_na_flags_reserved = ND_NA_FLAG_ROUTER |
- ND_NA_FLAG_SOLICITED;
-
- struct sockaddr_in6 dest = {AF_INET6, 0, 0, ALL_IPV6_NODES, 0};
- if (!ns_is_dad) // If not DAD, then unicast to source
- dest.sin6_addr = ip6->ip6_src;
-
- // Linux seems to not honor IPV6_PKTINFO on raw-sockets, so work around
- setsockopt(ping_socket, SOL_SOCKET, SO_BINDTODEVICE,
- iface->ifname, sizeof(iface->ifname));
- struct iovec iov = {&advert, sizeof(advert)};
- odhcpd_send(ping_socket, &dest, &iov, 1, iface);
- } else {
- // Send echo to all other interfaces to see where target is on
- // This will trigger neighbor discovery which is what we want.
- // We will observe the neighbor cache to see results.
-
- ssize_t sent = 0;
- struct interface *c;
- list_for_each_entry(c, &interfaces, head)
- if (iface->ndp == RELAYD_RELAY && iface != c &&
- (!ns_is_dad || !c->external == false))
- sent += ping6(&req->nd_ns_target, c);
-
- if (sent > 0) // Sent a ping, add pending neighbor entry
- modify_neighbor(&req->nd_ns_target, NULL, true);
- }