blob: 300966e0f308074ceedeff2e7ad28e2070256bcc [file] [log] [blame]
// Copyright 2017 The Chromium 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 "net/base/network_interfaces_fuchsia.h"
#include <fuchsia/hardware/ethernet/cpp/fidl.h>
#include <fuchsia/net/cpp/fidl.h>
#include <fuchsia/netstack/cpp/fidl.h>
#include <string>
#include <utility>
#include "base/format_macros.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/service_directory_client.h"
#include "base/strings/stringprintf.h"
#include "net/base/ip_endpoint.h"
#include "net/base/network_interfaces.h"
namespace net {
namespace internal {
namespace {
using ConnectionType = NetworkChangeNotifier::ConnectionType;
// Converts a Netstack NetInterface |interface| to a Chrome NetworkInterface.
// NetInterfaces may be bound to multiple IPv6 addresses. |address_index| is
// used to specify which address to use for the conversion.
// address_index = 0: Uses NetInterface::addr, NetInterface::netmask.
// address_index >= 1: Uses NetInterface::ipv6addrs[], with the array index
// offset by one.
NetworkInterface NetworkInterfaceFromAddress(
const fuchsia::netstack::NetInterface& interface,
size_t address_index) {
// TODO(sergeyu): attributes field is used to return address state for IPv6
// addresses. Currently Netstack doesn't provide this information.
const int attributes = 0;
IPAddress address;
uint8_t prefix_length;
if (address_index == 0) {
address = FuchsiaIpAddressToIPAddress(interface.addr);
prefix_length =
MaskPrefixLength(FuchsiaIpAddressToIPAddress(interface.netmask));
} else {
CHECK_LE(address_index, interface.ipv6addrs.size());
address = FuchsiaIpAddressToIPAddress(
interface.ipv6addrs.at(address_index - 1).addr);
prefix_length = interface.ipv6addrs.at(address_index - 1).prefix_len;
}
return NetworkInterface(interface.name, interface.name, interface.id,
ConvertConnectionType(interface), address,
prefix_length, attributes);
}
} // namespace
NetworkChangeNotifier::ConnectionType ConvertConnectionType(
const fuchsia::netstack::NetInterface& iface) {
if (!(iface.flags & fuchsia::netstack::NetInterfaceFlagUp)) {
return NetworkChangeNotifier::CONNECTION_NONE;
} else if (iface.features & fuchsia::hardware::ethernet::INFO_FEATURE_WLAN) {
return NetworkChangeNotifier::CONNECTION_WIFI;
}
return NetworkChangeNotifier::CONNECTION_UNKNOWN;
}
IPAddress FuchsiaIpAddressToIPAddress(const fuchsia::net::IpAddress& addr) {
if (addr.is_ipv4()) {
return IPAddress(addr.ipv4().addr.data(), addr.ipv4().addr.count());
}
if (addr.is_ipv6()) {
return IPAddress(addr.ipv6().addr.data(), addr.ipv6().addr.count());
}
return IPAddress();
}
std::vector<NetworkInterface> NetInterfaceToNetworkInterfaces(
const fuchsia::netstack::NetInterface& iface_in) {
std::vector<NetworkInterface> output;
// If the interface is not currently up then there are no addresses to return.
if (internal::ConvertConnectionType(iface_in) ==
NetworkChangeNotifier::CONNECTION_NONE) {
return output;
}
output.push_back(NetworkInterfaceFromAddress(iface_in, 0));
// Append interface entries for all additional IPv6 addresses.
for (size_t i = 0; i < iface_in.ipv6addrs.size(); ++i) {
output.push_back(NetworkInterfaceFromAddress(iface_in, i + 1));
}
return output;
}
} // namespace internal
bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
DCHECK(networks);
fuchsia::netstack::NetstackSyncPtr netstack =
base::fuchsia::ServiceDirectoryClient::ForCurrentProcess()
->ConnectToServiceSync<fuchsia::netstack::Netstack>();
// TODO(kmarshall): Use NetworkChangeNotifier's cached interface list.
std::vector<fuchsia::netstack::NetInterface> interfaces;
zx_status_t status = netstack->GetInterfaces(&interfaces);
if (status != ZX_OK) {
ZX_LOG(ERROR, status) << "fuchsia::netstack::GetInterfaces()";
return false;
}
for (auto& interface : interfaces) {
if ((internal::ConvertConnectionType(interface) ==
NetworkChangeNotifier::CONNECTION_NONE) ||
(interface.features &
fuchsia::hardware::ethernet::INFO_FEATURE_LOOPBACK)) {
continue;
}
auto converted = internal::NetInterfaceToNetworkInterfaces(interface);
std::move(converted.begin(), converted.end(),
std::back_inserter(*networks));
}
return true;
}
std::string GetWifiSSID() {
NOTIMPLEMENTED();
return std::string();
}
} // namespace net