1 // Copyright 2019 The Chromium Authors. All rights reserved.
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 "chromeos/components/sync_wifi/local_network_collector_impl.h"
6
7 #include "base/guid.h"
8 #include "chromeos/components/sync_wifi/network_eligibility_checker.h"
9 #include "chromeos/components/sync_wifi/network_identifier.h"
10 #include "chromeos/components/sync_wifi/network_type_conversions.h"
11 #include "chromeos/dbus/shill/shill_service_client.h"
12 #include "chromeos/network/network_event_log.h"
13 #include "chromeos/network/network_handler.h"
14 #include "chromeos/network/network_metadata_store.h"
15 #include "chromeos/network/network_state.h"
16 #include "chromeos/network/network_state_handler.h"
17 #include "chromeos/services/network_config/public/mojom/network_types.mojom-shared.h"
18 #include "components/device_event_log/device_event_log.h"
19 #include "components/sync/protocol/wifi_configuration_specifics.pb.h"
20 #include "dbus/object_path.h"
21 #include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
22
23 namespace chromeos {
24
25 namespace sync_wifi {
26
27 namespace {
28
GetServicePathForGuid(const std::string & guid)29 dbus::ObjectPath GetServicePathForGuid(const std::string& guid) {
30 const NetworkState* state =
31 NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid(
32 guid);
33 if (!state) {
34 return dbus::ObjectPath();
35 }
36
37 return dbus::ObjectPath(state->path());
38 }
39
40 } // namespace
41
LocalNetworkCollectorImpl(network_config::mojom::CrosNetworkConfig * cros_network_config)42 LocalNetworkCollectorImpl::LocalNetworkCollectorImpl(
43 network_config::mojom::CrosNetworkConfig* cros_network_config)
44 : cros_network_config_(cros_network_config) {
45 cros_network_config_->AddObserver(
46 cros_network_config_observer_receiver_.BindNewPipeAndPassRemote());
47
48 // Load the current list of networks.
49 OnNetworkStateListChanged();
50 }
51
52 LocalNetworkCollectorImpl::~LocalNetworkCollectorImpl() = default;
53
GetAllSyncableNetworks(ProtoListCallback callback)54 void LocalNetworkCollectorImpl::GetAllSyncableNetworks(
55 ProtoListCallback callback) {
56 std::string request_guid = InitializeRequest();
57 request_guid_to_list_callback_[request_guid] = std::move(callback);
58
59 int count = 0;
60 for (const network_config::mojom::NetworkStatePropertiesPtr& network :
61 mojo_networks_) {
62 if (!IsEligible(network)) {
63 continue;
64 }
65
66 request_guid_to_in_flight_networks_[request_guid].insert(
67 NetworkIdentifier::FromMojoNetwork(network));
68 StartGetNetworkDetails(network.get(), request_guid);
69 count++;
70 }
71
72 if (!count) {
73 OnRequestFinished(request_guid);
74 }
75 }
76
GetSyncableNetwork(const std::string & guid,ProtoCallback callback)77 void LocalNetworkCollectorImpl::GetSyncableNetwork(const std::string& guid,
78 ProtoCallback callback) {
79 const network_config::mojom::NetworkStateProperties* network = nullptr;
80 for (const network_config::mojom::NetworkStatePropertiesPtr& n :
81 mojo_networks_) {
82 if (n->guid == guid) {
83 if (IsEligible(n)) {
84 network = n.get();
85 }
86
87 break;
88 }
89 }
90
91 if (!network) {
92 std::move(callback).Run(base::nullopt);
93 return;
94 }
95
96 std::string request_guid = InitializeRequest();
97 request_guid_to_single_callback_[request_guid] = std::move(callback);
98
99 StartGetNetworkDetails(network, request_guid);
100 }
101
102 base::Optional<NetworkIdentifier>
GetNetworkIdentifierFromGuid(const std::string & guid)103 LocalNetworkCollectorImpl::GetNetworkIdentifierFromGuid(
104 const std::string& guid) {
105 for (const network_config::mojom::NetworkStatePropertiesPtr& network :
106 mojo_networks_) {
107 if (network->guid == guid) {
108 return NetworkIdentifier::FromMojoNetwork(network);
109 }
110 }
111 return base::nullopt;
112 }
113
SetNetworkMetadataStore(base::WeakPtr<NetworkMetadataStore> network_metadata_store)114 void LocalNetworkCollectorImpl::SetNetworkMetadataStore(
115 base::WeakPtr<NetworkMetadataStore> network_metadata_store) {
116 network_metadata_store_ = network_metadata_store;
117 }
118
InitializeRequest()119 std::string LocalNetworkCollectorImpl::InitializeRequest() {
120 std::string request_guid = base::GenerateGUID();
121 request_guid_to_complete_protos_[request_guid] =
122 std::vector<sync_pb::WifiConfigurationSpecifics>();
123 request_guid_to_in_flight_networks_[request_guid] =
124 base::flat_set<NetworkIdentifier>();
125 return request_guid;
126 }
127
IsEligible(const network_config::mojom::NetworkStatePropertiesPtr & network)128 bool LocalNetworkCollectorImpl::IsEligible(
129 const network_config::mojom::NetworkStatePropertiesPtr& network) {
130 if (!network || network->type != network_config::mojom::NetworkType::kWiFi) {
131 return false;
132 }
133
134 const network_config::mojom::WiFiStatePropertiesPtr& wifi_properties =
135 network->type_state->get_wifi();
136 return IsEligibleForSync(network->guid, network->connectable,
137 wifi_properties->security, network->source,
138 /*log_result=*/true);
139 }
140
StartGetNetworkDetails(const network_config::mojom::NetworkStateProperties * network,const std::string & request_guid)141 void LocalNetworkCollectorImpl::StartGetNetworkDetails(
142 const network_config::mojom::NetworkStateProperties* network,
143 const std::string& request_guid) {
144 sync_pb::WifiConfigurationSpecifics proto;
145 proto.set_hex_ssid(network->type_state->get_wifi()->hex_ssid);
146 proto.set_security_type(
147 SecurityTypeProtoFromMojo(network->type_state->get_wifi()->security));
148 base::TimeDelta timestamp =
149 network_metadata_store_->GetLastConnectedTimestamp(network->guid);
150 proto.set_last_connected_timestamp(timestamp.InMilliseconds());
151 cros_network_config_->GetManagedProperties(
152 network->guid,
153 base::BindOnce(&LocalNetworkCollectorImpl::OnGetManagedPropertiesResult,
154 weak_ptr_factory_.GetWeakPtr(), proto, request_guid));
155 }
156
OnGetManagedPropertiesResult(sync_pb::WifiConfigurationSpecifics proto,const std::string & request_guid,network_config::mojom::ManagedPropertiesPtr properties)157 void LocalNetworkCollectorImpl::OnGetManagedPropertiesResult(
158 sync_pb::WifiConfigurationSpecifics proto,
159 const std::string& request_guid,
160 network_config::mojom::ManagedPropertiesPtr properties) {
161 if (!properties) {
162 NET_LOG(ERROR) << "GetManagedProperties failed.";
163 OnNetworkFinished(NetworkIdentifier::FromProto(proto), request_guid);
164 return;
165 }
166 proto.set_automatically_connect(AutomaticallyConnectProtoFromMojo(
167 properties->type_properties->get_wifi()->auto_connect));
168 proto.set_is_preferred(IsPreferredProtoFromMojo(properties->priority));
169
170 if (properties->metered) {
171 proto.set_metered(
172 properties->metered->active_value
173 ? sync_pb::
174 WifiConfigurationSpecifics_MeteredOption_METERED_OPTION_YES
175 : sync_pb::
176 WifiConfigurationSpecifics_MeteredOption_METERED_OPTION_NO);
177 }
178
179 bool is_proxy_modified =
180 network_metadata_store_->GetIsFieldExternallyModified(
181 properties->guid, shill::kProxyConfigProperty);
182 sync_pb::WifiConfigurationSpecifics_ProxyConfiguration proxy_config =
183 ProxyConfigurationProtoFromMojo(properties->proxy_settings,
184 /*is_unspecified=*/is_proxy_modified);
185 proto.mutable_proxy_configuration()->CopyFrom(proxy_config);
186
187 bool is_dns_externally_modified =
188 network_metadata_store_->GetIsFieldExternallyModified(
189 properties->guid, shill::kNameServersProperty);
190 if (properties->static_ip_config &&
191 properties->static_ip_config->name_servers &&
192 (properties->source == network_config::mojom::OncSource::kUser ||
193 !is_dns_externally_modified)) {
194 proto.set_dns_option(
195 sync_pb::WifiConfigurationSpecifics_DnsOption_DNS_OPTION_CUSTOM);
196 for (const std::string& nameserver :
197 properties->static_ip_config->name_servers->active_value) {
198 proto.add_custom_dns(nameserver);
199 }
200 } else if (properties->source == network_config::mojom::OncSource::kDevice &&
201 is_dns_externally_modified) {
202 proto.set_dns_option(
203 sync_pb::WifiConfigurationSpecifics_DnsOption_DNS_OPTION_UNSPECIFIED);
204 } else {
205 proto.set_dns_option(
206 sync_pb::WifiConfigurationSpecifics_DnsOption_DNS_OPTION_DEFAULT_DHCP);
207 }
208
209 ShillServiceClient::Get()->GetWiFiPassphrase(
210 GetServicePathForGuid(properties->guid),
211 base::BindOnce(&LocalNetworkCollectorImpl::OnGetWiFiPassphraseResult,
212 weak_ptr_factory_.GetWeakPtr(), proto, request_guid),
213 base::BindOnce(&LocalNetworkCollectorImpl::OnGetWiFiPassphraseError,
214 weak_ptr_factory_.GetWeakPtr(),
215 NetworkIdentifier::FromProto(proto), request_guid));
216 }
217
OnGetWiFiPassphraseResult(sync_pb::WifiConfigurationSpecifics proto,const std::string & request_guid,const std::string & passphrase)218 void LocalNetworkCollectorImpl::OnGetWiFiPassphraseResult(
219 sync_pb::WifiConfigurationSpecifics proto,
220 const std::string& request_guid,
221 const std::string& passphrase) {
222 proto.set_passphrase(passphrase);
223 NetworkIdentifier id = NetworkIdentifier::FromProto(proto);
224 request_guid_to_complete_protos_[request_guid].push_back(std::move(proto));
225 OnNetworkFinished(id, request_guid);
226 }
227
OnGetWiFiPassphraseError(const NetworkIdentifier & id,const std::string & request_guid,const std::string & error_name,const std::string & error_message)228 void LocalNetworkCollectorImpl::OnGetWiFiPassphraseError(
229 const NetworkIdentifier& id,
230 const std::string& request_guid,
231 const std::string& error_name,
232 const std::string& error_message) {
233 NET_LOG(ERROR) << "Failed to get passphrase for " << id.SerializeToString()
234 << " Error: " << error_name << " Details: " << error_message;
235
236 OnNetworkFinished(id, request_guid);
237 }
238
OnNetworkFinished(const NetworkIdentifier & id,const std::string & request_guid)239 void LocalNetworkCollectorImpl::OnNetworkFinished(
240 const NetworkIdentifier& id,
241 const std::string& request_guid) {
242 request_guid_to_in_flight_networks_[request_guid].erase(id);
243
244 if (request_guid_to_in_flight_networks_[request_guid].empty()) {
245 OnRequestFinished(request_guid);
246 }
247 }
248
OnRequestFinished(const std::string & request_guid)249 void LocalNetworkCollectorImpl::OnRequestFinished(
250 const std::string& request_guid) {
251 DCHECK(request_guid_to_in_flight_networks_[request_guid].empty());
252
253 if (request_guid_to_single_callback_[request_guid]) {
254 std::vector<sync_pb::WifiConfigurationSpecifics>& list =
255 request_guid_to_complete_protos_[request_guid];
256 DCHECK(list.size() <= 1);
257 base::Optional<sync_pb::WifiConfigurationSpecifics> result;
258 if (list.size() == 1) {
259 result = list[0];
260 }
261 std::move(request_guid_to_single_callback_[request_guid]).Run(result);
262 request_guid_to_single_callback_.erase(request_guid);
263 } else {
264 ProtoListCallback callback =
265 std::move(request_guid_to_list_callback_[request_guid]);
266 DCHECK(callback);
267 std::move(callback).Run(request_guid_to_complete_protos_[request_guid]);
268 request_guid_to_list_callback_.erase(request_guid);
269 }
270
271 request_guid_to_complete_protos_.erase(request_guid);
272 request_guid_to_in_flight_networks_.erase(request_guid);
273 }
274
OnNetworkStateListChanged()275 void LocalNetworkCollectorImpl::OnNetworkStateListChanged() {
276 cros_network_config_->GetNetworkStateList(
277 network_config::mojom::NetworkFilter::New(
278 network_config::mojom::FilterType::kConfigured,
279 network_config::mojom::NetworkType::kWiFi,
280 /*limit=*/0),
281 base::BindOnce(&LocalNetworkCollectorImpl::OnGetNetworkList,
282 weak_ptr_factory_.GetWeakPtr()));
283 }
284
OnGetNetworkList(std::vector<network_config::mojom::NetworkStatePropertiesPtr> networks)285 void LocalNetworkCollectorImpl::OnGetNetworkList(
286 std::vector<network_config::mojom::NetworkStatePropertiesPtr> networks) {
287 mojo_networks_ = std::move(networks);
288 }
289
290 } // namespace sync_wifi
291
292 } // namespace chromeos
293