// 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 #include #include #include "base/format_macros.h" #include "base/fuchsia/component_context.h" #include "base/fuchsia/fuchsia_logging.h" #include "base/strings/stringprintf.h" #include "net/base/ip_endpoint.h" #include "net/base/network_change_notifier.h" #include "net/base/network_interfaces.h" namespace net { namespace internal { namespace { using ConnectionType = NetworkChangeNotifier::ConnectionType; ConnectionType ConvertConnectionType( const fuchsia::netstack::NetInterface& iface) { return iface.features & fuchsia::netstack::interfaceFeatureWlan ? NetworkChangeNotifier::CONNECTION_WIFI : NetworkChangeNotifier::CONNECTION_UNKNOWN; } // 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 = NetAddressToIPAddress(interface.addr); prefix_length = MaskPrefixLength(NetAddressToIPAddress(interface.netmask)); } else { CHECK_LE(address_index, interface.ipv6addrs->size()); address = NetAddressToIPAddress(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 IPAddress NetAddressToIPAddress(const fuchsia::netstack::NetAddress& addr) { if (addr.ipv4) { return IPAddress(addr.ipv4->addr.data(), addr.ipv4->addr.count()); } if (addr.ipv6) { return IPAddress(addr.ipv6->addr.data(), addr.ipv6->addr.count()); } return IPAddress(); } std::vector NetInterfaceToNetworkInterfaces( const fuchsia::netstack::NetInterface& iface_in) { std::vector output; // Check if the interface is up. if (!(iface_in.flags & fuchsia::netstack::NetInterfaceFlagUp)) return output; // Skip loopback. if (iface_in.features & fuchsia::netstack::interfaceFeatureLoopback) 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::ComponentContext::GetDefault() ->ConnectToServiceSync(); // TODO(kmarshall): Use NetworkChangeNotifier's cached interface list. fidl::VectorPtr 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.get()) { 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