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.
5 #include "chrome/browser/chromeos/net/network_portal_detector_impl.h"
10 #include "base/command_line.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/histogram.h"
14 #include "base/strings/stringprintf.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chromeos/dbus/dbus_thread_manager.h"
17 #include "chromeos/dbus/shill_profile_client.h"
18 #include "chromeos/login/login_state.h"
19 #include "chromeos/network/network_event_log.h"
20 #include "chromeos/network/network_state.h"
21 #include "chromeos/network/network_state_handler.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/common/content_switches.h"
24 #include "net/http/http_status_code.h"
25 #include "third_party/cros_system_api/dbus/service_constants.h"
27 using base::StringPrintf
;
28 using captive_portal::CaptivePortalDetector
;
34 // Delay before portal detection caused by changes in proxy settings.
35 const int kProxyChangeDelaySec
= 1;
37 // Maximum number of reports from captive portal detector about
38 // offline state in a row before notification is sent to observers.
39 const int kMaxOfflineResultsBeforeReport
= 3;
41 // Delay before portal detection attempt after !ONLINE -> !ONLINE
43 const int kShortInitialDelayBetweenAttemptsMs
= 600;
45 // Maximum timeout before portal detection attempts after !ONLINE ->
46 // !ONLINE transition.
47 const int kShortMaximumDelayBetweenAttemptsMs
= 2 * 60 * 1000;
49 // Delay before portal detection attempt after !ONLINE -> ONLINE
51 const int kLongInitialDelayBetweenAttemptsMs
= 30 * 1000;
53 // Maximum timeout before portal detection attempts after !ONLINE ->
55 const int kLongMaximumDelayBetweenAttemptsMs
= 5 * 60 * 1000;
57 const NetworkState
* DefaultNetwork() {
58 return NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
62 return LoginState::IsInitialized() && LoginState::Get()->IsUserLoggedIn();
65 void RecordDetectionResult(NetworkPortalDetector::CaptivePortalStatus status
) {
67 UMA_HISTOGRAM_ENUMERATION(
68 NetworkPortalDetectorImpl::kSessionDetectionResultHistogram
,
70 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
72 UMA_HISTOGRAM_ENUMERATION(
73 NetworkPortalDetectorImpl::kOobeDetectionResultHistogram
,
75 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
79 void RecordDetectionDuration(const base::TimeDelta
& duration
) {
81 UMA_HISTOGRAM_MEDIUM_TIMES(
82 NetworkPortalDetectorImpl::kSessionDetectionDurationHistogram
,
85 UMA_HISTOGRAM_MEDIUM_TIMES(
86 NetworkPortalDetectorImpl::kOobeDetectionDurationHistogram
, duration
);
90 void RecordDiscrepancyWithShill(
91 const NetworkState
* network
,
92 const NetworkPortalDetector::CaptivePortalStatus status
) {
94 if (network
->connection_state() == shill::kStateOnline
) {
95 UMA_HISTOGRAM_ENUMERATION(
96 NetworkPortalDetectorImpl::kSessionShillOnlineHistogram
,
98 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
99 } else if (network
->connection_state() == shill::kStatePortal
) {
100 UMA_HISTOGRAM_ENUMERATION(
101 NetworkPortalDetectorImpl::kSessionShillPortalHistogram
,
103 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
104 } else if (network
->connection_state() == shill::kStateOffline
) {
105 UMA_HISTOGRAM_ENUMERATION(
106 NetworkPortalDetectorImpl::kSessionShillOfflineHistogram
,
108 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
111 if (network
->connection_state() == shill::kStateOnline
) {
112 UMA_HISTOGRAM_ENUMERATION(
113 NetworkPortalDetectorImpl::kOobeShillOnlineHistogram
,
115 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
116 } else if (network
->connection_state() == shill::kStatePortal
) {
117 UMA_HISTOGRAM_ENUMERATION(
118 NetworkPortalDetectorImpl::kOobeShillPortalHistogram
,
120 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
121 } else if (network
->connection_state() == shill::kStateOffline
) {
122 UMA_HISTOGRAM_ENUMERATION(
123 NetworkPortalDetectorImpl::kOobeShillOfflineHistogram
,
125 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
);
130 void RecordPortalToOnlineTransition(const base::TimeDelta
& duration
) {
132 UMA_HISTOGRAM_LONG_TIMES(
133 NetworkPortalDetectorImpl::kSessionPortalToOnlineHistogram
,
136 UMA_HISTOGRAM_LONG_TIMES(
137 NetworkPortalDetectorImpl::kOobePortalToOnlineHistogram
,
144 ////////////////////////////////////////////////////////////////////////////////
145 // NetworkPortalDetectorImpl::DetectionAttemptCompletedLogState
147 NetworkPortalDetectorImpl::DetectionAttemptCompletedReport::
148 DetectionAttemptCompletedReport()
149 : result(captive_portal::RESULT_COUNT
), response_code(-1) {
152 NetworkPortalDetectorImpl::DetectionAttemptCompletedReport::
153 DetectionAttemptCompletedReport(const std::string network_name
,
154 const std::string network_id
,
155 captive_portal::CaptivePortalResult result
,
157 : network_name(network_name
),
158 network_id(network_id
),
160 response_code(response_code
) {
163 void NetworkPortalDetectorImpl::DetectionAttemptCompletedReport::Report()
165 // TODO (ygorshenin@): remove VLOG as soon as NET_LOG_EVENT will be dumped on
166 // a disk, crbug.com/293739.
167 VLOG(1) << "Detection attempt completed: "
168 << "name=" << network_name
<< ", "
169 << "id=" << network_id
<< ", "
170 << "result=" << captive_portal::CaptivePortalResultToString(result
)
172 << "response_code=" << response_code
;
173 NET_LOG_EVENT(StringPrintf(
174 "Portal detection completed: network_id=%s, result=%s, "
177 captive_portal::CaptivePortalResultToString(result
).c_str(),
182 bool NetworkPortalDetectorImpl::DetectionAttemptCompletedReport::Equals(
183 const DetectionAttemptCompletedReport
& o
) const {
184 return network_name
== o
.network_name
&& network_id
== o
.network_id
&&
185 result
== o
.result
&& response_code
== o
.response_code
;
188 ////////////////////////////////////////////////////////////////////////////////
189 // NetworkPortalDetectorImpl, public:
191 const char NetworkPortalDetectorImpl::kOobeDetectionResultHistogram
[] =
192 "CaptivePortal.OOBE.DetectionResult";
193 const char NetworkPortalDetectorImpl::kOobeDetectionDurationHistogram
[] =
194 "CaptivePortal.OOBE.DetectionDuration";
195 const char NetworkPortalDetectorImpl::kOobeShillOnlineHistogram
[] =
196 "CaptivePortal.OOBE.DiscrepancyWithShill_Online";
197 const char NetworkPortalDetectorImpl::kOobeShillPortalHistogram
[] =
198 "CaptivePortal.OOBE.DiscrepancyWithShill_RestrictedPool";
199 const char NetworkPortalDetectorImpl::kOobeShillOfflineHistogram
[] =
200 "CaptivePortal.OOBE.DiscrepancyWithShill_Offline";
201 const char NetworkPortalDetectorImpl::kOobePortalToOnlineHistogram
[] =
202 "CaptivePortal.OOBE.PortalToOnlineTransition";
204 const char NetworkPortalDetectorImpl::kSessionDetectionResultHistogram
[] =
205 "CaptivePortal.Session.DetectionResult";
206 const char NetworkPortalDetectorImpl::kSessionDetectionDurationHistogram
[] =
207 "CaptivePortal.Session.DetectionDuration";
208 const char NetworkPortalDetectorImpl::kSessionShillOnlineHistogram
[] =
209 "CaptivePortal.Session.DiscrepancyWithShill_Online";
210 const char NetworkPortalDetectorImpl::kSessionShillPortalHistogram
[] =
211 "CaptivePortal.Session.DiscrepancyWithShill_RestrictedPool";
212 const char NetworkPortalDetectorImpl::kSessionShillOfflineHistogram
[] =
213 "CaptivePortal.Session.DiscrepancyWithShill_Offline";
214 const char NetworkPortalDetectorImpl::kSessionPortalToOnlineHistogram
[] =
215 "CaptivePortal.Session.PortalToOnlineTransition";
218 void NetworkPortalDetectorImpl::Initialize(
219 net::URLRequestContextGetter
* url_context
) {
220 if (NetworkPortalDetector::set_for_testing())
222 CHECK(!NetworkPortalDetector::network_portal_detector())
223 << "NetworkPortalDetector was initialized twice.";
224 if (CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTestType
))
225 set_network_portal_detector(new NetworkPortalDetectorStubImpl());
227 set_network_portal_detector(new NetworkPortalDetectorImpl(url_context
));
230 NetworkPortalDetectorImpl::NetworkPortalDetectorImpl(
231 const scoped_refptr
<net::URLRequestContextGetter
>& request_context
)
232 : state_(STATE_IDLE
),
233 test_url_(CaptivePortalDetector::kDefaultURL
),
235 strategy_(PortalDetectorStrategy::CreateById(
236 PortalDetectorStrategy::STRATEGY_ID_LOGIN_SCREEN
, this)),
237 last_detection_result_(CAPTIVE_PORTAL_STATUS_UNKNOWN
),
238 same_detection_result_count_(0),
239 no_response_result_count_(0),
240 weak_factory_(this) {
241 captive_portal_detector_
.reset(new CaptivePortalDetector(request_context
));
244 chrome::NOTIFICATION_LOGIN_PROXY_CHANGED
,
245 content::NotificationService::AllSources());
247 chrome::NOTIFICATION_AUTH_SUPPLIED
,
248 content::NotificationService::AllSources());
250 chrome::NOTIFICATION_AUTH_CANCELLED
,
251 content::NotificationService::AllSources());
253 NetworkHandler::Get()->network_state_handler()->AddObserver(this, FROM_HERE
);
254 StartDetectionIfIdle();
257 NetworkPortalDetectorImpl::~NetworkPortalDetectorImpl() {
258 DCHECK(CalledOnValidThread());
260 attempt_task_
.Cancel();
261 attempt_timeout_
.Cancel();
263 captive_portal_detector_
->Cancel();
264 captive_portal_detector_
.reset();
266 if (NetworkHandler::IsInitialized()) {
267 NetworkHandler::Get()->network_state_handler()->RemoveObserver(this,
272 void NetworkPortalDetectorImpl::AddObserver(Observer
* observer
) {
273 DCHECK(CalledOnValidThread());
274 if (observer
&& !observers_
.HasObserver(observer
))
275 observers_
.AddObserver(observer
);
278 void NetworkPortalDetectorImpl::AddAndFireObserver(Observer
* observer
) {
279 DCHECK(CalledOnValidThread());
282 AddObserver(observer
);
283 CaptivePortalState portal_state
;
284 const NetworkState
* network
= DefaultNetwork();
286 portal_state
= GetCaptivePortalState(network
->guid());
287 observer
->OnPortalDetectionCompleted(network
, portal_state
);
290 void NetworkPortalDetectorImpl::RemoveObserver(Observer
* observer
) {
291 DCHECK(CalledOnValidThread());
293 observers_
.RemoveObserver(observer
);
296 bool NetworkPortalDetectorImpl::IsEnabled() { return enabled_
; }
298 void NetworkPortalDetectorImpl::Enable(bool start_detection
) {
299 DCHECK(CalledOnValidThread());
306 const NetworkState
* network
= DefaultNetwork();
307 if (!start_detection
|| !network
)
309 NET_LOG_EVENT(StringPrintf("Starting detection attempt: network_id=%s",
310 network
->guid().c_str()),
312 portal_state_map_
.erase(network
->guid());
316 NetworkPortalDetectorImpl::CaptivePortalState
317 NetworkPortalDetectorImpl::GetCaptivePortalState(const std::string
& guid
) {
318 DCHECK(CalledOnValidThread());
319 CaptivePortalStateMap::const_iterator it
= portal_state_map_
.find(guid
);
320 if (it
== portal_state_map_
.end())
321 return CaptivePortalState();
325 bool NetworkPortalDetectorImpl::StartDetectionIfIdle() {
332 void NetworkPortalDetectorImpl::SetStrategy(
333 PortalDetectorStrategy::StrategyId id
) {
334 if (id
== strategy_
->Id())
336 strategy_
= PortalDetectorStrategy::CreateById(id
, this).Pass();
338 StartDetectionIfIdle();
341 void NetworkPortalDetectorImpl::DefaultNetworkChanged(
342 const NetworkState
* default_network
) {
343 DCHECK(CalledOnValidThread());
345 if (!default_network
) {
346 NET_LOG_EVENT("Default network changed", "None");
348 default_network_name_
.clear();
352 CaptivePortalState state
;
353 state
.status
= CAPTIVE_PORTAL_STATUS_OFFLINE
;
354 OnDetectionCompleted(NULL
, state
);
358 default_network_name_
= default_network
->name();
360 bool network_changed
= (default_network_id_
!= default_network
->guid());
361 default_network_id_
= default_network
->guid();
363 bool connection_state_changed
=
364 (default_connection_state_
!= default_network
->connection_state());
365 default_connection_state_
= default_network
->connection_state();
367 NET_LOG_EVENT(StringPrintf(
368 "Default network changed: network_id=%s, state=%s, "
369 "changed=%d, state_changed=%d",
370 default_network_id_
.c_str(),
371 default_connection_state_
.c_str(),
373 connection_state_changed
),
374 default_network_name_
);
376 if (network_changed
|| connection_state_changed
)
379 if (is_idle() && NetworkState::StateIsConnected(default_connection_state_
)) {
380 // Initiate Captive Portal detection if network's captive
381 // portal state is unknown (e.g. for freshly created networks),
382 // offline or if network connection state was changed.
383 CaptivePortalState state
= GetCaptivePortalState(default_network
->guid());
384 if (state
.status
== CAPTIVE_PORTAL_STATUS_UNKNOWN
||
385 state
.status
== CAPTIVE_PORTAL_STATUS_OFFLINE
||
386 (!network_changed
&& connection_state_changed
)) {
387 ScheduleAttempt(base::TimeDelta());
392 int NetworkPortalDetectorImpl::NoResponseResultCount() {
393 return no_response_result_count_
;
396 base::TimeTicks
NetworkPortalDetectorImpl::AttemptStartTime() {
397 return attempt_start_time_
;
400 base::TimeTicks
NetworkPortalDetectorImpl::GetCurrentTimeTicks() {
401 if (time_ticks_for_testing_
.is_null())
402 return base::TimeTicks::Now();
403 return time_ticks_for_testing_
;
407 ////////////////////////////////////////////////////////////////////////////////
408 // NetworkPortalDetectorImpl, private:
410 void NetworkPortalDetectorImpl::StartDetection() {
413 ResetStrategyAndCounters();
414 detection_start_time_
= GetCurrentTimeTicks();
415 ScheduleAttempt(base::TimeDelta());
418 void NetworkPortalDetectorImpl::StopDetection() {
419 attempt_task_
.Cancel();
420 attempt_timeout_
.Cancel();
421 captive_portal_detector_
->Cancel();
423 ResetStrategyAndCounters();
426 void NetworkPortalDetectorImpl::ScheduleAttempt(const base::TimeDelta
& delay
) {
432 attempt_task_
.Cancel();
433 attempt_timeout_
.Cancel();
434 state_
= STATE_PORTAL_CHECK_PENDING
;
436 next_attempt_delay_
= std::max(delay
, strategy_
->GetDelayTillNextAttempt());
437 attempt_task_
.Reset(base::Bind(&NetworkPortalDetectorImpl::StartAttempt
,
438 weak_factory_
.GetWeakPtr()));
439 base::MessageLoop::current()->PostDelayedTask(
440 FROM_HERE
, attempt_task_
.callback(), next_attempt_delay_
);
443 void NetworkPortalDetectorImpl::StartAttempt() {
444 DCHECK(is_portal_check_pending());
446 state_
= STATE_CHECKING_FOR_PORTAL
;
447 attempt_start_time_
= GetCurrentTimeTicks();
449 captive_portal_detector_
->DetectCaptivePortal(
451 base::Bind(&NetworkPortalDetectorImpl::OnAttemptCompleted
,
452 weak_factory_
.GetWeakPtr()));
453 attempt_timeout_
.Reset(
454 base::Bind(&NetworkPortalDetectorImpl::OnAttemptTimeout
,
455 weak_factory_
.GetWeakPtr()));
457 base::MessageLoop::current()->PostDelayedTask(
459 attempt_timeout_
.callback(),
460 strategy_
->GetNextAttemptTimeout());
463 void NetworkPortalDetectorImpl::OnAttemptTimeout() {
464 DCHECK(CalledOnValidThread());
465 DCHECK(is_checking_for_portal());
467 NET_LOG_ERROR(StringPrintf("Portal detection timeout: network_id=%s",
468 default_network_id_
.c_str()),
469 default_network_name_
);
471 captive_portal_detector_
->Cancel();
472 CaptivePortalDetector::Results results
;
473 results
.result
= captive_portal::RESULT_NO_RESPONSE
;
474 OnAttemptCompleted(results
);
477 void NetworkPortalDetectorImpl::OnAttemptCompleted(
478 const CaptivePortalDetector::Results
& results
) {
479 DCHECK(CalledOnValidThread());
480 DCHECK(is_checking_for_portal());
482 captive_portal::CaptivePortalResult result
= results
.result
;
483 int response_code
= results
.response_code
;
485 const NetworkState
* network
= DefaultNetwork();
487 // If using a fake profile client, also fake being behind a captive portal
488 // if the default network is in portal state.
489 if (result
!= captive_portal::RESULT_NO_RESPONSE
&&
490 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface() &&
491 network
&& network
->connection_state() == shill::kStatePortal
) {
492 result
= captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL
;
496 DetectionAttemptCompletedReport
attempt_completed_report(
497 default_network_name_
, default_network_id_
, result
, response_code
);
498 if (!attempt_completed_report_
.Equals(attempt_completed_report
)) {
499 attempt_completed_report_
= attempt_completed_report
;
500 attempt_completed_report_
.Report();
504 attempt_timeout_
.Cancel();
506 CaptivePortalState state
;
507 state
.response_code
= response_code
;
508 state
.time
= GetCurrentTimeTicks();
510 case captive_portal::RESULT_NO_RESPONSE
:
511 if (state
.response_code
== net::HTTP_PROXY_AUTHENTICATION_REQUIRED
) {
512 state
.status
= CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED
;
513 } else if (network
&&
514 (network
->connection_state() == shill::kStatePortal
)) {
515 // Take into account shill's detection results.
516 state
.status
= CAPTIVE_PORTAL_STATUS_PORTAL
;
518 state
.status
= CAPTIVE_PORTAL_STATUS_OFFLINE
;
521 case captive_portal::RESULT_INTERNET_CONNECTED
:
522 state
.status
= CAPTIVE_PORTAL_STATUS_ONLINE
;
524 case captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL
:
525 state
.status
= CAPTIVE_PORTAL_STATUS_PORTAL
;
531 if (last_detection_result_
!= state
.status
) {
532 last_detection_result_
= state
.status
;
533 same_detection_result_count_
= 1;
534 net::BackoffEntry::Policy policy
= strategy_
->policy();
535 if (state
.status
== CAPTIVE_PORTAL_STATUS_ONLINE
) {
536 policy
.initial_delay_ms
= kLongInitialDelayBetweenAttemptsMs
;
537 policy
.maximum_backoff_ms
= kLongMaximumDelayBetweenAttemptsMs
;
539 policy
.initial_delay_ms
= kShortInitialDelayBetweenAttemptsMs
;
540 policy
.maximum_backoff_ms
= kShortMaximumDelayBetweenAttemptsMs
;
542 strategy_
->SetPolicyAndReset(policy
);
544 ++same_detection_result_count_
;
546 strategy_
->OnDetectionCompleted();
548 if (result
== captive_portal::RESULT_NO_RESPONSE
)
549 ++no_response_result_count_
;
551 no_response_result_count_
= 0;
553 if (state
.status
!= CAPTIVE_PORTAL_STATUS_OFFLINE
||
554 same_detection_result_count_
>= kMaxOfflineResultsBeforeReport
) {
555 OnDetectionCompleted(network
, state
);
557 ScheduleAttempt(results
.retry_after_delta
);
560 void NetworkPortalDetectorImpl::Observe(
562 const content::NotificationSource
& source
,
563 const content::NotificationDetails
& details
) {
564 if (type
== chrome::NOTIFICATION_LOGIN_PROXY_CHANGED
||
565 type
== chrome::NOTIFICATION_AUTH_SUPPLIED
||
566 type
== chrome::NOTIFICATION_AUTH_CANCELLED
) {
568 "Restarting portal detection due to proxy change",
569 default_network_name_
.empty() ? "None" : default_network_name_
);
571 ScheduleAttempt(base::TimeDelta::FromSeconds(kProxyChangeDelaySec
));
575 void NetworkPortalDetectorImpl::OnDetectionCompleted(
576 const NetworkState
* network
,
577 const CaptivePortalState
& state
) {
579 NotifyDetectionCompleted(network
, state
);
583 CaptivePortalStateMap::const_iterator it
=
584 portal_state_map_
.find(network
->guid());
585 if (it
== portal_state_map_
.end() || it
->second
.status
!= state
.status
||
586 it
->second
.response_code
!= state
.response_code
) {
587 // Record detection duration iff detection result differs from the
588 // previous one for this network. The reason is to record all stats
589 // only when network changes it's state.
590 RecordDetectionStats(network
, state
.status
);
591 if (it
!= portal_state_map_
.end() &&
592 it
->second
.status
== CAPTIVE_PORTAL_STATUS_PORTAL
&&
593 state
.status
== CAPTIVE_PORTAL_STATUS_ONLINE
) {
594 RecordPortalToOnlineTransition(state
.time
- it
->second
.time
);
597 portal_state_map_
[network
->guid()] = state
;
599 NotifyDetectionCompleted(network
, state
);
602 void NetworkPortalDetectorImpl::NotifyDetectionCompleted(
603 const NetworkState
* network
,
604 const CaptivePortalState
& state
) {
606 Observer
, observers_
, OnPortalDetectionCompleted(network
, state
));
607 notification_controller_
.OnPortalDetectionCompleted(network
, state
);
610 bool NetworkPortalDetectorImpl::AttemptTimeoutIsCancelledForTesting() const {
611 return attempt_timeout_
.IsCancelled();
614 void NetworkPortalDetectorImpl::RecordDetectionStats(
615 const NetworkState
* network
,
616 CaptivePortalStatus status
) {
617 // Don't record stats for offline state.
621 if (!detection_start_time_
.is_null())
622 RecordDetectionDuration(GetCurrentTimeTicks() - detection_start_time_
);
623 RecordDetectionResult(status
);
626 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN
:
629 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE
:
630 if (network
->connection_state() == shill::kStateOnline
||
631 network
->connection_state() == shill::kStatePortal
) {
632 RecordDiscrepancyWithShill(network
, status
);
635 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE
:
636 if (network
->connection_state() != shill::kStateOnline
)
637 RecordDiscrepancyWithShill(network
, status
);
639 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL
:
640 if (network
->connection_state() != shill::kStatePortal
)
641 RecordDiscrepancyWithShill(network
, status
);
643 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED
:
644 if (network
->connection_state() != shill::kStateOnline
)
645 RecordDiscrepancyWithShill(network
, status
);
647 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT
:
653 void NetworkPortalDetectorImpl::ResetStrategyAndCounters() {
654 last_detection_result_
= CAPTIVE_PORTAL_STATUS_UNKNOWN
;
655 same_detection_result_count_
= 0;
656 no_response_result_count_
= 0;
660 } // namespace chromeos