Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chromeos / network / network_connection_handler.cc
1 // Copyright (c) 2013 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/network/network_connection_handler.h"
6
7 #include "base/bind.h"
8 #include "base/json/json_reader.h"
9 #include "base/location.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "chromeos/cert_loader.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_manager_client.h"
15 #include "chromeos/dbus/shill_service_client.h"
16 #include "chromeos/network/certificate_pattern.h"
17 #include "chromeos/network/client_cert_resolver.h"
18 #include "chromeos/network/client_cert_util.h"
19 #include "chromeos/network/managed_network_configuration_handler.h"
20 #include "chromeos/network/network_configuration_handler.h"
21 #include "chromeos/network/network_event_log.h"
22 #include "chromeos/network/network_handler_callbacks.h"
23 #include "chromeos/network/network_profile_handler.h"
24 #include "chromeos/network/network_state.h"
25 #include "chromeos/network/network_state_handler.h"
26 #include "chromeos/network/shill_property_util.h"
27 #include "dbus/object_path.h"
28 #include "net/cert/x509_certificate.h"
29 #include "third_party/cros_system_api/dbus/service_constants.h"
30
31 namespace chromeos {
32
33 namespace {
34
35 void InvokeErrorCallback(const std::string& service_path,
36                          const network_handler::ErrorCallback& error_callback,
37                          const std::string& error_name) {
38   NET_LOG_ERROR("Connect Error: " + error_name, service_path);
39   network_handler::RunErrorCallback(
40       error_callback, service_path, error_name, "");
41 }
42
43 bool IsAuthenticationError(const std::string& error) {
44   return (error == shill::kErrorBadWEPKey ||
45           error == shill::kErrorPppAuthFailed ||
46           error == shill::kErrorEapLocalTlsFailed ||
47           error == shill::kErrorEapRemoteTlsFailed ||
48           error == shill::kErrorEapAuthenticationFailed);
49 }
50
51 bool VPNRequiresCredentials(const std::string& service_path,
52                            const std::string& provider_type,
53                            const base::DictionaryValue& provider_properties) {
54   if (provider_type == shill::kProviderOpenVpn) {
55     std::string username;
56     provider_properties.GetStringWithoutPathExpansion(
57         shill::kOpenVPNUserProperty, &username);
58     if (username.empty()) {
59       NET_LOG_EVENT("OpenVPN: No username", service_path);
60       return true;
61     }
62     bool passphrase_required = false;
63     provider_properties.GetBooleanWithoutPathExpansion(
64         shill::kPassphraseRequiredProperty, &passphrase_required);
65     if (passphrase_required) {
66       NET_LOG_EVENT("OpenVPN: Passphrase Required", service_path);
67       return true;
68     }
69     NET_LOG_EVENT("OpenVPN Is Configured", service_path);
70   } else {
71     bool passphrase_required = false;
72     provider_properties.GetBooleanWithoutPathExpansion(
73         shill::kL2tpIpsecPskRequiredProperty, &passphrase_required);
74     if (passphrase_required) {
75       NET_LOG_EVENT("VPN: PSK Required", service_path);
76       return true;
77     }
78     provider_properties.GetBooleanWithoutPathExpansion(
79         shill::kPassphraseRequiredProperty, &passphrase_required);
80     if (passphrase_required) {
81       NET_LOG_EVENT("VPN: Passphrase Required", service_path);
82       return true;
83     }
84     NET_LOG_EVENT("VPN Is Configured", service_path);
85   }
86   return false;
87 }
88
89 std::string GetDefaultUserProfilePath(const NetworkState* network) {
90   if (!NetworkHandler::IsInitialized() ||
91       (LoginState::IsInitialized() &&
92        !LoginState::Get()->UserHasNetworkProfile()) ||
93       (network && network->type() == shill::kTypeWifi &&
94        network->security() == shill::kSecurityNone)) {
95     return NetworkProfileHandler::GetSharedProfilePath();
96   }
97   const NetworkProfile* profile  =
98       NetworkHandler::Get()->network_profile_handler()->GetDefaultUserProfile();
99   return profile ? profile->path
100                  : NetworkProfileHandler::GetSharedProfilePath();
101 }
102
103 }  // namespace
104
105 const char NetworkConnectionHandler::kErrorNotFound[] = "not-found";
106 const char NetworkConnectionHandler::kErrorConnected[] = "connected";
107 const char NetworkConnectionHandler::kErrorConnecting[] = "connecting";
108 const char NetworkConnectionHandler::kErrorNotConnected[] = "not-connected";
109 const char NetworkConnectionHandler::kErrorPassphraseRequired[] =
110     "passphrase-required";
111 const char NetworkConnectionHandler::kErrorActivationRequired[] =
112     "activation-required";
113 const char NetworkConnectionHandler::kErrorCertificateRequired[] =
114     "certificate-required";
115 const char NetworkConnectionHandler::kErrorConfigurationRequired[] =
116     "configuration-required";
117 const char NetworkConnectionHandler::kErrorAuthenticationRequired[] =
118     "authentication-required";
119 const char NetworkConnectionHandler::kErrorShillError[] = "shill-error";
120 const char NetworkConnectionHandler::kErrorConfigureFailed[] =
121     "configure-failed";
122 const char NetworkConnectionHandler::kErrorConnectCanceled[] =
123     "connect-canceled";
124 const char NetworkConnectionHandler::kErrorCertLoadTimeout[] =
125     "cert-load-timeout";
126
127 struct NetworkConnectionHandler::ConnectRequest {
128   ConnectRequest(const std::string& service_path,
129                  const std::string& profile_path,
130                  const base::Closure& success,
131                  const network_handler::ErrorCallback& error)
132       : service_path(service_path),
133         profile_path(profile_path),
134         connect_state(CONNECT_REQUESTED),
135         success_callback(success),
136         error_callback(error) {
137   }
138   enum ConnectState {
139     CONNECT_REQUESTED = 0,
140     CONNECT_STARTED = 1,
141     CONNECT_CONNECTING = 2
142   };
143   std::string service_path;
144   std::string profile_path;
145   ConnectState connect_state;
146   base::Closure success_callback;
147   network_handler::ErrorCallback error_callback;
148 };
149
150 NetworkConnectionHandler::NetworkConnectionHandler()
151     : cert_loader_(NULL),
152       network_state_handler_(NULL),
153       configuration_handler_(NULL),
154       logged_in_(false),
155       certificates_loaded_(false) {
156 }
157
158 NetworkConnectionHandler::~NetworkConnectionHandler() {
159   if (network_state_handler_)
160     network_state_handler_->RemoveObserver(this, FROM_HERE);
161   if (cert_loader_)
162     cert_loader_->RemoveObserver(this);
163   if (LoginState::IsInitialized())
164     LoginState::Get()->RemoveObserver(this);
165 }
166
167 void NetworkConnectionHandler::Init(
168     NetworkStateHandler* network_state_handler,
169     NetworkConfigurationHandler* network_configuration_handler,
170     ManagedNetworkConfigurationHandler* managed_network_configuration_handler) {
171   if (LoginState::IsInitialized())
172     LoginState::Get()->AddObserver(this);
173
174   if (CertLoader::IsInitialized()) {
175     cert_loader_ = CertLoader::Get();
176     cert_loader_->AddObserver(this);
177     if (cert_loader_->certificates_loaded()) {
178       NET_LOG_EVENT("Certificates Loaded", "");
179       certificates_loaded_ = true;
180     }
181   } else {
182     // TODO(tbarzic): Require a mock or stub cert_loader in tests.
183     NET_LOG_EVENT("Certificate Loader not initialized", "");
184     certificates_loaded_ = true;
185   }
186
187   if (network_state_handler) {
188     network_state_handler_ = network_state_handler;
189     network_state_handler_->AddObserver(this, FROM_HERE);
190   }
191   configuration_handler_ = network_configuration_handler;
192   managed_configuration_handler_ = managed_network_configuration_handler;
193
194   // After this point, the NetworkConnectionHandler is fully initialized (all
195   // handler references set, observers registered, ...).
196
197   if (LoginState::IsInitialized())
198     LoggedInStateChanged();
199 }
200
201 void NetworkConnectionHandler::AddObserver(Observer* observer) {
202   observers_.AddObserver(observer);
203 }
204
205 void NetworkConnectionHandler::RemoveObserver(Observer* observer) {
206   observers_.RemoveObserver(observer);
207 }
208
209 void NetworkConnectionHandler::LoggedInStateChanged() {
210   LoginState* login_state = LoginState::Get();
211   if (logged_in_ || !login_state->IsUserLoggedIn())
212     return;
213
214   NET_LOG_EVENT("Logged In", "");
215   logged_in_ = true;
216   logged_in_time_ = base::TimeTicks::Now();
217 }
218
219 void NetworkConnectionHandler::OnCertificatesLoaded(
220     const net::CertificateList& cert_list,
221     bool initial_load) {
222   certificates_loaded_ = true;
223   NET_LOG_EVENT("Certificates Loaded", "");
224   if (queued_connect_)
225     ConnectToQueuedNetwork();
226 }
227
228 void NetworkConnectionHandler::ConnectToNetwork(
229     const std::string& service_path,
230     const base::Closure& success_callback,
231     const network_handler::ErrorCallback& error_callback,
232     bool check_error_state) {
233   NET_LOG_USER("ConnectToNetwork", service_path);
234   FOR_EACH_OBSERVER(Observer, observers_,
235                     ConnectToNetworkRequested(service_path));
236
237   // Clear any existing queued connect request.
238   queued_connect_.reset();
239   if (HasConnectingNetwork(service_path)) {
240     NET_LOG_USER("Connect Request While Pending", service_path);
241     InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
242     return;
243   }
244
245   // Check cached network state for connected, connecting, or unactivated
246   // networks. These states will not be affected by a recent configuration.
247   // Note: NetworkState may not exist for a network that was recently
248   // configured, in which case these checks do not apply anyway.
249   const NetworkState* network =
250       network_state_handler_->GetNetworkState(service_path);
251
252   if (network) {
253     // For existing networks, perform some immediate consistency checks.
254     if (network->IsConnectedState()) {
255       InvokeErrorCallback(service_path, error_callback, kErrorConnected);
256       return;
257     }
258     if (network->IsConnectingState()) {
259       InvokeErrorCallback(service_path, error_callback, kErrorConnecting);
260       return;
261     }
262
263     if (check_error_state) {
264       const std::string& error = network->last_error();
265       if (error == shill::kErrorBadPassphrase) {
266         InvokeErrorCallback(service_path, error_callback, error);
267         return;
268       }
269       if (IsAuthenticationError(error)) {
270         InvokeErrorCallback(
271             service_path, error_callback, kErrorAuthenticationRequired);
272         return;
273       }
274     }
275   }
276
277   // If the network does not have a profile path, specify the correct default
278   // profile here and set it once connected. Otherwise leave it empty to
279   // indicate that it does not need to be set.
280   std::string profile_path;
281   if (!network || network->profile_path().empty())
282     profile_path = GetDefaultUserProfilePath(network);
283
284   // All synchronous checks passed, add |service_path| to connecting list.
285   pending_requests_.insert(std::make_pair(
286       service_path,
287       ConnectRequest(service_path, profile_path,
288                      success_callback, error_callback)));
289
290   // Connect immediately to 'connectable' networks.
291   // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
292   if (network && network->connectable() && network->type() != shill::kTypeVPN) {
293     CallShillConnect(service_path);
294     return;
295   }
296
297   // Request additional properties to check. VerifyConfiguredAndConnect will
298   // use only these properties, not cached properties, to ensure that they
299   // are up to date after any recent configuration.
300   configuration_handler_->GetProperties(
301       service_path,
302       base::Bind(&NetworkConnectionHandler::VerifyConfiguredAndConnect,
303                  AsWeakPtr(), check_error_state),
304       base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
305                  AsWeakPtr(), service_path));
306 }
307
308 void NetworkConnectionHandler::DisconnectNetwork(
309     const std::string& service_path,
310     const base::Closure& success_callback,
311     const network_handler::ErrorCallback& error_callback) {
312   NET_LOG_USER("DisconnectNetwork", service_path);
313   const NetworkState* network =
314       network_state_handler_->GetNetworkState(service_path);
315   if (!network) {
316     InvokeErrorCallback(service_path, error_callback, kErrorNotFound);
317     return;
318   }
319   if (!network->IsConnectedState() && !network->IsConnectingState()) {
320     InvokeErrorCallback(service_path, error_callback, kErrorNotConnected);
321     return;
322   }
323   pending_requests_.erase(service_path);
324   CallShillDisconnect(service_path, success_callback, error_callback);
325 }
326
327 bool NetworkConnectionHandler::HasConnectingNetwork(
328     const std::string& service_path) {
329   return pending_requests_.count(service_path) != 0;
330 }
331
332 bool NetworkConnectionHandler::HasPendingConnectRequest() {
333   return pending_requests_.size() > 0;
334 }
335
336 void NetworkConnectionHandler::NetworkListChanged() {
337   CheckAllPendingRequests();
338 }
339
340 void NetworkConnectionHandler::NetworkPropertiesUpdated(
341     const NetworkState* network) {
342   if (HasConnectingNetwork(network->path()))
343     CheckPendingRequest(network->path());
344 }
345
346 NetworkConnectionHandler::ConnectRequest*
347 NetworkConnectionHandler::GetPendingRequest(const std::string& service_path) {
348   std::map<std::string, ConnectRequest>::iterator iter =
349       pending_requests_.find(service_path);
350   return iter != pending_requests_.end() ? &(iter->second) : NULL;
351 }
352
353 // ConnectToNetwork implementation
354
355 void NetworkConnectionHandler::VerifyConfiguredAndConnect(
356     bool check_error_state,
357     const std::string& service_path,
358     const base::DictionaryValue& service_properties) {
359   NET_LOG_EVENT("VerifyConfiguredAndConnect", service_path);
360
361   // If 'passphrase_required' is still true, then the 'Passphrase' property
362   // has not been set to a minimum length value.
363   bool passphrase_required = false;
364   service_properties.GetBooleanWithoutPathExpansion(
365       shill::kPassphraseRequiredProperty, &passphrase_required);
366   if (passphrase_required) {
367     ErrorCallbackForPendingRequest(service_path, kErrorPassphraseRequired);
368     return;
369   }
370
371   std::string type, security;
372   service_properties.GetStringWithoutPathExpansion(shill::kTypeProperty, &type);
373   service_properties.GetStringWithoutPathExpansion(
374       shill::kSecurityProperty, &security);
375   bool connectable = false;
376   service_properties.GetBooleanWithoutPathExpansion(
377       shill::kConnectableProperty, &connectable);
378
379   // In case NetworkState was not available in ConnectToNetwork (e.g. it had
380   // been recently configured), we need to check Connectable again.
381   if (connectable && type != shill::kTypeVPN) {
382     // TODO(stevenjb): Shill needs to properly set Connectable for VPN.
383     CallShillConnect(service_path);
384     return;
385   }
386
387   // Get VPN provider type and host (required for configuration) and ensure
388   // that required VPN non-cert properties are set.
389   const base::DictionaryValue* provider_properties = NULL;
390   std::string vpn_provider_type, vpn_provider_host, vpn_client_cert_id;
391   if (type == shill::kTypeVPN) {
392     // VPN Provider values are read from the "Provider" dictionary, not the
393     // "Provider.Type", etc keys (which are used only to set the values).
394     if (service_properties.GetDictionaryWithoutPathExpansion(
395             shill::kProviderProperty, &provider_properties)) {
396       provider_properties->GetStringWithoutPathExpansion(
397           shill::kTypeProperty, &vpn_provider_type);
398       provider_properties->GetStringWithoutPathExpansion(
399           shill::kHostProperty, &vpn_provider_host);
400       provider_properties->GetStringWithoutPathExpansion(
401           shill::kL2tpIpsecClientCertIdProperty, &vpn_client_cert_id);
402     }
403     if (vpn_provider_type.empty() || vpn_provider_host.empty()) {
404       ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
405       return;
406     }
407   }
408
409   std::string guid;
410   service_properties.GetStringWithoutPathExpansion(shill::kGuidProperty, &guid);
411   std::string profile;
412   service_properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
413                                                    &profile);
414   const base::DictionaryValue* user_policy =
415       managed_configuration_handler_->FindPolicyByGuidAndProfile(guid, profile);
416
417   client_cert::ClientCertConfig cert_config_from_policy;
418   if (user_policy)
419     client_cert::OncToClientCertConfig(*user_policy, &cert_config_from_policy);
420
421   client_cert::ConfigType client_cert_type = client_cert::CONFIG_TYPE_NONE;
422   if (type == shill::kTypeVPN) {
423     if (vpn_provider_type == shill::kProviderOpenVpn) {
424       client_cert_type = client_cert::CONFIG_TYPE_OPENVPN;
425     } else {
426       // L2TP/IPSec only requires a certificate if one is specified in ONC
427       // or one was configured by the UI. Otherwise it is L2TP/IPSec with
428       // PSK and doesn't require a certificate.
429       //
430       // TODO(benchan): Modify shill to specify the authentication type via
431       // the kL2tpIpsecAuthenticationType property, so that Chrome doesn't need
432       // to deduce the authentication type based on the
433       // kL2tpIpsecClientCertIdProperty here (and also in VPNConfigView).
434       if (!vpn_client_cert_id.empty() ||
435           cert_config_from_policy.client_cert_type !=
436               onc::client_cert::kClientCertTypeNone) {
437         client_cert_type = client_cert::CONFIG_TYPE_IPSEC;
438       }
439     }
440   } else if (type == shill::kTypeWifi && security == shill::kSecurity8021x) {
441     client_cert_type = client_cert::CONFIG_TYPE_EAP;
442   }
443
444   base::DictionaryValue config_properties;
445   if (client_cert_type != client_cert::CONFIG_TYPE_NONE) {
446     // Note: if we get here then a certificate *may* be required, so we want
447     // to ensure that certificates have loaded successfully before attempting
448     // to connect.
449
450     // User must be logged in to connect to a network requiring a certificate.
451     if (!logged_in_ || !cert_loader_) {
452       NET_LOG_ERROR("User not logged in", "");
453       ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
454       return;
455     }
456     // If certificates have not been loaded yet, queue the connect request.
457     if (!certificates_loaded_) {
458       NET_LOG_EVENT("Certificates not loaded", "");
459       QueueConnectRequest(service_path);
460       return;
461     }
462
463     // Check certificate properties from policy.
464     if (cert_config_from_policy.client_cert_type ==
465         onc::client_cert::kPattern) {
466       if (!ClientCertResolver::ResolveCertificatePatternSync(
467               client_cert_type,
468               cert_config_from_policy.pattern,
469               &config_properties)) {
470         ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
471         return;
472       }
473     } else if (check_error_state &&
474                !client_cert::IsCertificateConfigured(client_cert_type,
475                                                      service_properties)) {
476       // Network may not be configured.
477       ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
478       return;
479     }
480   }
481
482   if (type == shill::kTypeVPN) {
483     // VPN may require a username, and/or passphrase to be set. (Check after
484     // ensuring that any required certificates are configured).
485     DCHECK(provider_properties);
486     if (VPNRequiresCredentials(
487             service_path, vpn_provider_type, *provider_properties)) {
488       NET_LOG_USER("VPN Requires Credentials", service_path);
489       ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
490       return;
491     }
492
493     // If it's L2TP/IPsec PSK, there is no properties to configure, so proceed
494     // to connect.
495     if (client_cert_type == client_cert::CONFIG_TYPE_NONE) {
496       CallShillConnect(service_path);
497       return;
498     }
499   }
500
501   if (!config_properties.empty()) {
502     NET_LOG_EVENT("Configuring Network", service_path);
503     configuration_handler_->SetProperties(
504         service_path,
505         config_properties,
506         base::Bind(&NetworkConnectionHandler::CallShillConnect,
507                    AsWeakPtr(),
508                    service_path),
509         base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure,
510                    AsWeakPtr(),
511                    service_path));
512     return;
513   }
514
515   // Otherwise, we probably still need to configure the network since
516   // 'Connectable' is false. If |check_error_state| is true, signal an
517   // error, otherwise attempt to connect to possibly gain additional error
518   // state from Shill (or in case 'Connectable' is improperly unset).
519   if (check_error_state)
520     ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired);
521   else
522     CallShillConnect(service_path);
523 }
524
525 void NetworkConnectionHandler::QueueConnectRequest(
526     const std::string& service_path) {
527   ConnectRequest* request = GetPendingRequest(service_path);
528   if (!request) {
529     NET_LOG_ERROR("No pending request to queue", service_path);
530     return;
531   }
532
533   const int kMaxCertLoadTimeSeconds = 15;
534   base::TimeDelta dtime = base::TimeTicks::Now() - logged_in_time_;
535   if (dtime > base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds)) {
536     NET_LOG_ERROR("Certificate load timeout", service_path);
537     InvokeErrorCallback(service_path,
538                         request->error_callback,
539                         kErrorCertLoadTimeout);
540     return;
541   }
542
543   NET_LOG_EVENT("Connect Request Queued", service_path);
544   queued_connect_.reset(new ConnectRequest(
545       service_path, request->profile_path,
546       request->success_callback, request->error_callback));
547   pending_requests_.erase(service_path);
548
549   // Post a delayed task to check to see if certificates have loaded. If they
550   // haven't, and queued_connect_ has not been cleared (e.g. by a successful
551   // connect request), cancel the request and notify the user.
552   base::MessageLoopProxy::current()->PostDelayedTask(
553       FROM_HERE,
554       base::Bind(&NetworkConnectionHandler::CheckCertificatesLoaded,
555                  AsWeakPtr()),
556       base::TimeDelta::FromSeconds(kMaxCertLoadTimeSeconds) - dtime);
557 }
558
559 void NetworkConnectionHandler::CheckCertificatesLoaded() {
560   if (certificates_loaded_)
561     return;
562   // If queued_connect_ has been cleared (e.g. another connect request occurred
563   // and wasn't queued), do nothing here.
564   if (!queued_connect_)
565     return;
566   // Otherwise, notify the user.
567   NET_LOG_ERROR("Certificate load timeout", queued_connect_->service_path);
568   InvokeErrorCallback(queued_connect_->service_path,
569                       queued_connect_->error_callback,
570                       kErrorCertLoadTimeout);
571   queued_connect_.reset();
572 }
573
574 void NetworkConnectionHandler::ConnectToQueuedNetwork() {
575   DCHECK(queued_connect_);
576
577   // Make a copy of |queued_connect_| parameters, because |queued_connect_|
578   // will get reset at the beginning of |ConnectToNetwork|.
579   std::string service_path = queued_connect_->service_path;
580   base::Closure success_callback = queued_connect_->success_callback;
581   network_handler::ErrorCallback error_callback =
582       queued_connect_->error_callback;
583
584   NET_LOG_EVENT("Connecting to Queued Network", service_path);
585   ConnectToNetwork(service_path, success_callback, error_callback,
586                    false /* check_error_state */);
587 }
588
589 void NetworkConnectionHandler::CallShillConnect(
590     const std::string& service_path) {
591   NET_LOG_EVENT("Sending Connect Request to Shill", service_path);
592   network_state_handler_->ClearLastErrorForNetwork(service_path);
593   DBusThreadManager::Get()->GetShillServiceClient()->Connect(
594       dbus::ObjectPath(service_path),
595       base::Bind(&NetworkConnectionHandler::HandleShillConnectSuccess,
596                  AsWeakPtr(), service_path),
597       base::Bind(&NetworkConnectionHandler::HandleShillConnectFailure,
598                  AsWeakPtr(), service_path));
599 }
600
601 void NetworkConnectionHandler::HandleConfigurationFailure(
602     const std::string& service_path,
603     const std::string& error_name,
604     scoped_ptr<base::DictionaryValue> error_data) {
605   ConnectRequest* request = GetPendingRequest(service_path);
606   if (!request) {
607     NET_LOG_ERROR("HandleConfigurationFailure called with no pending request.",
608                   service_path);
609     return;
610   }
611   network_handler::ErrorCallback error_callback = request->error_callback;
612   pending_requests_.erase(service_path);
613   if (!error_callback.is_null())
614     error_callback.Run(kErrorConfigureFailed, error_data.Pass());
615 }
616
617 void NetworkConnectionHandler::HandleShillConnectSuccess(
618     const std::string& service_path) {
619   ConnectRequest* request = GetPendingRequest(service_path);
620   if (!request) {
621     NET_LOG_ERROR("HandleShillConnectSuccess called with no pending request.",
622                   service_path);
623     return;
624   }
625   request->connect_state = ConnectRequest::CONNECT_STARTED;
626   NET_LOG_EVENT("Connect Request Acknowledged", service_path);
627   // Do not call success_callback here, wait for one of the following
628   // conditions:
629   // * State transitions to a non connecting state indicating success or failure
630   // * Network is no longer in the visible list, indicating failure
631   CheckPendingRequest(service_path);
632 }
633
634 void NetworkConnectionHandler::HandleShillConnectFailure(
635     const std::string& service_path,
636     const std::string& dbus_error_name,
637     const std::string& dbus_error_message) {
638   ConnectRequest* request = GetPendingRequest(service_path);
639   if (!request) {
640     NET_LOG_ERROR("HandleShillConnectFailure called with no pending request.",
641                   service_path);
642     return;
643   }
644   network_handler::ErrorCallback error_callback = request->error_callback;
645   pending_requests_.erase(service_path);
646   network_handler::ShillErrorCallbackFunction(
647       shill::kErrorConnectFailed, service_path, error_callback,
648       dbus_error_name, dbus_error_message);
649 }
650
651 void NetworkConnectionHandler::CheckPendingRequest(
652     const std::string service_path) {
653   ConnectRequest* request = GetPendingRequest(service_path);
654   DCHECK(request);
655   if (request->connect_state == ConnectRequest::CONNECT_REQUESTED)
656     return;  // Request has not started, ignore update
657   const NetworkState* network =
658       network_state_handler_->GetNetworkState(service_path);
659   if (!network)
660     return;  // NetworkState may not be be updated yet.
661
662   if (network->IsConnectingState()) {
663     request->connect_state = ConnectRequest::CONNECT_CONNECTING;
664     return;
665   }
666   if (network->IsConnectedState()) {
667     NET_LOG_EVENT("Connect Request Succeeded", service_path);
668     if (!request->profile_path.empty()) {
669       // If a profile path was specified, set it on a successful connection.
670       configuration_handler_->SetNetworkProfile(
671           service_path,
672           request->profile_path,
673           base::Bind(&base::DoNothing),
674           chromeos::network_handler::ErrorCallback());
675     }
676     if (!request->success_callback.is_null())
677       request->success_callback.Run();
678     pending_requests_.erase(service_path);
679     return;
680   }
681   if (network->connection_state() == shill::kStateIdle &&
682       request->connect_state != ConnectRequest::CONNECT_CONNECTING) {
683     // Connection hasn't started yet, keep waiting.
684     return;
685   }
686
687   // Network is neither connecting or connected; an error occurred.
688   std::string error_name;  // 'Canceled' or 'Failed'
689   if (network->connection_state() == shill::kStateIdle &&
690       pending_requests_.size() > 1) {
691     // Another connect request canceled this one.
692     error_name = kErrorConnectCanceled;
693   } else {
694     error_name = shill::kErrorConnectFailed;
695     if (network->connection_state() != shill::kStateFailure) {
696       NET_LOG_ERROR("Unexpected State: " + network->connection_state(),
697                     service_path);
698     }
699   }
700
701   network_handler::ErrorCallback error_callback = request->error_callback;
702   pending_requests_.erase(service_path);
703   if (error_callback.is_null()) {
704     NET_LOG_ERROR("Connect Error, no callback: " + error_name, service_path);
705     return;
706   }
707   InvokeErrorCallback(service_path, error_callback, error_name);
708 }
709
710 void NetworkConnectionHandler::CheckAllPendingRequests() {
711   for (std::map<std::string, ConnectRequest>::iterator iter =
712            pending_requests_.begin(); iter != pending_requests_.end(); ++iter) {
713     CheckPendingRequest(iter->first);
714   }
715 }
716
717 void NetworkConnectionHandler::ErrorCallbackForPendingRequest(
718     const std::string& service_path,
719     const std::string& error_name) {
720   ConnectRequest* request = GetPendingRequest(service_path);
721   if (!request) {
722     NET_LOG_ERROR("ErrorCallbackForPendingRequest with no pending request.",
723                   service_path);
724     return;
725   }
726   // Remove the entry before invoking the callback in case it triggers a retry.
727   network_handler::ErrorCallback error_callback = request->error_callback;
728   pending_requests_.erase(service_path);
729   InvokeErrorCallback(service_path, error_callback, error_name);
730 }
731
732 // Disconnect
733
734 void NetworkConnectionHandler::CallShillDisconnect(
735     const std::string& service_path,
736     const base::Closure& success_callback,
737     const network_handler::ErrorCallback& error_callback) {
738   NET_LOG_USER("Disconnect Request", service_path);
739   DBusThreadManager::Get()->GetShillServiceClient()->Disconnect(
740       dbus::ObjectPath(service_path),
741       base::Bind(&NetworkConnectionHandler::HandleShillDisconnectSuccess,
742                  AsWeakPtr(), service_path, success_callback),
743       base::Bind(&network_handler::ShillErrorCallbackFunction,
744                  kErrorShillError, service_path, error_callback));
745 }
746
747 void NetworkConnectionHandler::HandleShillDisconnectSuccess(
748     const std::string& service_path,
749     const base::Closure& success_callback) {
750   NET_LOG_EVENT("Disconnect Request Sent", service_path);
751   if (!success_callback.is_null())
752     success_callback.Run();
753 }
754
755 }  // namespace chromeos