blob: b544cab6094bb9606552b2fede63833f4ed81a04 [file] [log] [blame]
// Copyright 2016 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "arc-networkd/neighbor_finder.h"
#include <arpa/inet.h>
#include <netinet/icmp6.h>
#include <string.h>
#include <ndp.h>
#include <base/message_loop/message_loop.h>
namespace {
const int kTimeoutMs = 1000;
} // namespace
namespace arc_networkd {
bool NeighborFinder::Check(const std::string& ifname,
const struct in6_addr& addr,
const base::Callback<void(bool)>& callback) {
struct ndp_msg* msg;
CHECK(!running_);
memcpy(&check_addr_, &addr, sizeof(check_addr_));
result_callback_ = callback;
running_ = true;
StartNdp(ifname, NDP_MSG_NA);
base::MessageLoopForIO::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&NeighborFinder::Timeout,
weak_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(kTimeoutMs));
CHECK_EQ(ndp_msg_new(&msg, NDP_MSG_NS), 0);
ndp_msg_ifindex_set(msg, ifindex_);
struct nd_neighbor_solicit** ns =
reinterpret_cast<struct nd_neighbor_solicit**>(ndp_msgns(msg));
memcpy(&(*ns)->nd_ns_target, &addr, sizeof((*ns)->nd_ns_target));
if (ndp_msg_send(ndp_, msg))
LOG(WARNING) << "Error sending neighbor solicitation";
ndp_msg_destroy(msg);
return true;
}
void NeighborFinder::Timeout() {
if (!running_)
return;
running_ = false;
StopNdp();
result_callback_.Run(false);
}
int NeighborFinder::OnNdpMsg(struct ndp* ndp, struct ndp_msg* msg) {
if (!running_)
return 0;
if (memcmp(&check_addr_, ndp_msg_addrto(msg), sizeof(check_addr_)) == 0) {
running_ = false;
StopNdp();
result_callback_.Run(true);
}
return 0;
}
} // namespace arc_networkd