1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/base/network_interfaces_fuchsia.h"
6
7 #include <fuchsia/net/interfaces/cpp/fidl.h>
8 #include <zircon/types.h>
9
10 #include <string>
11 #include <utility>
12
13 #include "base/logging.h"
14 #include "net/base/fuchsia/network_interface_cache.h"
15 #include "net/base/network_change_notifier.h"
16 #include "net/base/network_change_notifier_fuchsia.h"
17 #include "net/base/network_interfaces.h"
18 #include "third_party/abseil-cpp/absl/types/optional.h"
19
20 namespace net {
21 namespace internal {
22 namespace {
23
FuchsiaIpAddressToIPAddress(const fuchsia::net::IpAddress & address)24 IPAddress FuchsiaIpAddressToIPAddress(const fuchsia::net::IpAddress& address) {
25 switch (address.Which()) {
26 case fuchsia::net::IpAddress::kIpv4:
27 return IPAddress(address.ipv4().addr.data(), address.ipv4().addr.size());
28 case fuchsia::net::IpAddress::kIpv6:
29 return IPAddress(address.ipv6().addr.data(), address.ipv6().addr.size());
30 default:
31 return IPAddress();
32 }
33 }
34
35 } // namespace
36
37 // static
VerifyAndCreate(fuchsia::net::interfaces::Properties properties)38 absl::optional<InterfaceProperties> InterfaceProperties::VerifyAndCreate(
39 fuchsia::net::interfaces::Properties properties) {
40 if (!internal::VerifyCompleteInterfaceProperties(properties))
41 return absl::nullopt;
42 return absl::make_optional(InterfaceProperties(std::move(properties)));
43 }
44
InterfaceProperties(fuchsia::net::interfaces::Properties properties)45 InterfaceProperties::InterfaceProperties(
46 fuchsia::net::interfaces::Properties properties)
47 : properties_(std::move(properties)) {}
48
49 InterfaceProperties::InterfaceProperties(InterfaceProperties&& interface) =
50 default;
51
52 InterfaceProperties& InterfaceProperties::operator=(
53 InterfaceProperties&& interface) = default;
54
55 InterfaceProperties::~InterfaceProperties() = default;
56
Update(fuchsia::net::interfaces::Properties properties)57 bool InterfaceProperties::Update(
58 fuchsia::net::interfaces::Properties properties) {
59 if (!properties.has_id() || properties_.id() != properties.id()) {
60 LOG(ERROR) << "Update failed: invalid properties.";
61 return false;
62 }
63
64 if (properties.has_addresses()) {
65 for (const auto& fidl_address : properties.addresses()) {
66 if (!fidl_address.has_addr()) {
67 LOG(ERROR) << "Update failed: invalid properties.";
68 return false;
69 }
70 }
71 properties_.set_addresses(std::move(*properties.mutable_addresses()));
72 }
73
74 if (properties.has_online())
75 properties_.set_online(properties.online());
76 if (properties.has_has_default_ipv4_route())
77 properties_.set_has_default_ipv4_route(properties.has_default_ipv4_route());
78 if (properties.has_has_default_ipv6_route())
79 properties_.set_has_default_ipv6_route(properties.has_default_ipv6_route());
80
81 return true;
82 }
83
AppendNetworkInterfaces(NetworkInterfaceList * interfaces) const84 void InterfaceProperties::AppendNetworkInterfaces(
85 NetworkInterfaceList* interfaces) const {
86 for (const auto& fidl_address : properties_.addresses()) {
87 IPAddress address = FuchsiaIpAddressToIPAddress(fidl_address.addr().addr);
88 if (address.empty()) {
89 LOG(WARNING) << "Unknown fuchsia.net/IpAddress variant "
90 << fidl_address.addr().addr.Which();
91 continue;
92 }
93
94 const int kAttributes = 0;
95 interfaces->emplace_back(
96 properties_.name(), properties_.name(), properties_.id(),
97 internal::ConvertConnectionType(properties_.device_class()),
98 std::move(address), fidl_address.addr().prefix_len, kAttributes);
99 }
100 }
101
IsPubliclyRoutable() const102 bool InterfaceProperties::IsPubliclyRoutable() const {
103 if (!properties_.online())
104 return false;
105
106 for (const auto& fidl_address : properties_.addresses()) {
107 const IPAddress address =
108 FuchsiaIpAddressToIPAddress(fidl_address.addr().addr);
109 if ((address.IsIPv4() && properties_.has_default_ipv4_route() &&
110 !address.IsLinkLocal()) ||
111 (address.IsIPv6() && properties_.has_default_ipv6_route() &&
112 address.IsPubliclyRoutable())) {
113 return true;
114 }
115 }
116 return false;
117 }
118
ConvertConnectionType(const fuchsia::net::interfaces::DeviceClass & device_class)119 NetworkChangeNotifier::ConnectionType ConvertConnectionType(
120 const fuchsia::net::interfaces::DeviceClass& device_class) {
121 switch (device_class.Which()) {
122 case fuchsia::net::interfaces::DeviceClass::kLoopback:
123 return NetworkChangeNotifier::CONNECTION_NONE;
124 case fuchsia::net::interfaces::DeviceClass::kDevice:
125 switch (device_class.device()) {
126 case fuchsia::hardware::network::DeviceClass::WLAN:
127 return NetworkChangeNotifier::CONNECTION_WIFI;
128 case fuchsia::hardware::network::DeviceClass::ETHERNET:
129 return NetworkChangeNotifier::CONNECTION_ETHERNET;
130 default:
131 return NetworkChangeNotifier::CONNECTION_UNKNOWN;
132 }
133 default:
134 LOG(WARNING) << "Received unknown fuchsia.net.interfaces/DeviceClass "
135 << device_class.Which();
136 return NetworkChangeNotifier::CONNECTION_UNKNOWN;
137 }
138 }
139
VerifyCompleteInterfaceProperties(const fuchsia::net::interfaces::Properties & properties)140 bool VerifyCompleteInterfaceProperties(
141 const fuchsia::net::interfaces::Properties& properties) {
142 if (!properties.has_id())
143 return false;
144 if (!properties.has_addresses())
145 return false;
146 for (const auto& fidl_address : properties.addresses()) {
147 if (!fidl_address.has_addr())
148 return false;
149 }
150 if (!properties.has_online())
151 return false;
152 if (!properties.has_device_class())
153 return false;
154 if (!properties.has_has_default_ipv4_route())
155 return false;
156 if (!properties.has_has_default_ipv6_route())
157 return false;
158 if (!properties.has_name()) {
159 return false;
160 }
161 return true;
162 }
163
164 } // namespace internal
165
GetNetworkList(NetworkInterfaceList * networks,int policy)166 bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
167 DCHECK(networks);
168
169 const internal::NetworkInterfaceCache* cache_ptr =
170 NetworkChangeNotifier::GetNetworkInterfaceCache();
171 if (cache_ptr) {
172 return cache_ptr->GetOnlineInterfaces(networks);
173 }
174
175 fuchsia::net::interfaces::WatcherHandle watcher_handle =
176 internal::ConnectInterfacesWatcher();
177 std::vector<fuchsia::net::interfaces::Properties> interfaces;
178
179 auto handle_or_status = internal::ReadExistingNetworkInterfacesFromNewWatcher(
180 std::move(watcher_handle), interfaces);
181 if (!handle_or_status.has_value()) {
182 return false;
183 }
184
185 internal::NetworkInterfaceCache temp_cache(/*require_wlan=*/false);
186 auto change_bits = temp_cache.AddInterfaces(std::move(interfaces));
187 if (!change_bits.has_value()) {
188 return false;
189 }
190
191 return temp_cache.GetOnlineInterfaces(networks);
192 }
193
GetWifiSSID()194 std::string GetWifiSSID() {
195 NOTIMPLEMENTED();
196 return std::string();
197 }
198
199 } // namespace net
200