blob: 3c3606fafa571383ea310c65ae3b19bc42c20a27 [file] [log] [blame]
Wade Guthriea60a11c2013-04-12 17:47:34 -07001// Copyright (c) 2013 The Chromium OS 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#ifndef SHILL_SCAN_SESSION_H_
6#define SHILL_SCAN_SESSION_H_
7
Wade Guthrieb9c3feb2013-04-25 16:31:19 -07008#include <deque>
9#include <set>
Wade Guthriea60a11c2013-04-12 17:47:34 -070010#include <vector>
11
12#include <base/basictypes.h>
Wade Guthrieb9c3feb2013-04-25 16:31:19 -070013#include <base/callback.h>
14#include <base/memory/weak_ptr.h>
15#include <gtest/gtest_prod.h> // for FRIEND_TEST
Wade Guthrief22681f2013-05-31 11:46:31 -070016#include <metrics/timer.h>
Wade Guthriea60a11c2013-04-12 17:47:34 -070017
Wade Guthrieb9c3feb2013-04-25 16:31:19 -070018#include "shill/byte_string.h"
Wade Guthrie84db7ce2013-06-12 11:40:49 -070019#include "shill/netlink_manager.h"
Wade Guthriea60a11c2013-04-12 17:47:34 -070020#include "shill/wifi_provider.h"
21
22namespace shill {
23
Wade Guthrieb9c3feb2013-04-25 16:31:19 -070024class EventDispatcher;
Wade Guthrief22681f2013-05-31 11:46:31 -070025class Metrics;
Wade Guthrieb9c3feb2013-04-25 16:31:19 -070026class NetlinkManager;
27class NetlinkMessage;
Wade Guthrie7347bf22013-04-30 11:21:51 -070028class Nl80211Message;
Wade Guthrieb9c3feb2013-04-25 16:31:19 -070029
30// |ScanSession| sends requests to the kernel to scan WiFi frequencies for
31// access points. The sequence for a single scan is as follows:
Wade Guthriea60a11c2013-04-12 17:47:34 -070032//
33// +-------------+ +--------+
34// | ScanSession | | Kernel |
35// +---+---------+ +-----+--+
36// |--- NL80211_CMD_TRIGGER_SCAN ---------------------------------->|
37// |<-- NL80211_CMD_TRIGGER_SCAN (broadcast) -----------------------|
38// |<-- NL80211_CMD_NEW_SCAN_RESULTS (broadcast) -------------------|
39// |--- NL80211_CMD_GET_SCAN -------------------------------------->|
40// |<-- NL80211_CMD_NEW_SCAN_RESULTS (reply, unicast, NLM_F_MULTI) -|
41// |<-- NL80211_CMD_NEW_SCAN_RESULTS (reply, unicast, NLM_F_MULTI) -|
42// | ... |
43// |<-- NL80211_CMD_NEW_SCAN_RESULTS (reply, unicast, NLM_F_MULTI) -|
44// | |
45//
Wade Guthrieb9c3feb2013-04-25 16:31:19 -070046// Scanning WiFi frequencies for access points takes a long time (on the order
47// of 100ms per frequency and the kernel doesn't return the result until the
48// answers are ready for all the frequencies in the batch). Given this,
49// scanning all frequencies in one batch takes a very long time.
50//
51// A ScanSession is used to distribute a scan across multiple requests (hoping
52// that a successful connection will result from an early request thereby
53// obviating the need for the remainder of the scan). A ScanSession can be
54// used as follows (note, this is shown as synchronous code for clarity
55// but it really should be implemented as asynchronous code):
56//
57// ScanSession::FractionList scan_fractions;
58// scan_fractions.push_back(<some value>);
59// ...
60// scan_fractions.push_back(<some value>);
61// ScanSession scan_session(netlink_manager_, dispatcher(),
62// frequencies_seen_ever, all_scan_frequencies_,
63// interface_index(), scan_fractions,
64// kMinScanFrequencies, kMaxScanFrequencies,
65// on_scan_failed);
66// while (scan_session.HasMoreFrequencies()) {
67// scan_session.InitiateScan();
68// // Wait for scan results. In the current WiFi code, this means wait
69// // until |WiFi::ScanDone| is called.
70// }
Wade Guthriea60a11c2013-04-12 17:47:34 -070071
72class ScanSession {
73 public:
Wade Guthrieb9c3feb2013-04-25 16:31:19 -070074 typedef base::Closure OnScanFailed;
75 typedef std::deque<float> FractionList;
76 // Used as a fraction in |FractionList| to indicate that future scans in
77 // this session should not be limited to a subset of the frequencies we've
78 // already seen.
79 static const float kAllFrequencies;
80
81 // Sets up a new progressive scan session. Uses |netlink_manager| to send
82 // NL80211_CMD_TRIGGER_SCAN messages to the kernel (uses |dispatcher| to
83 // reissue those commands if a send request returns EBUSY). Multiple scans
84 // for APs on wifi device |ifindex| are issued (one for each call to
85 // |InitiateScan|) on wifi frequencies taken from the union of unique
86 // frequencies in |previous_frequencies| and |available_frequencies| (most
87 // commonly seen frequencies before less commonly seen ones followed by
88 // never-before seen frequencies, the latter in an unspecified order).
89 //
90 // Each scan takes a greater percentile (described by the values in
91 // |fractions|) of the previously seen frequencies (but no less than
92 // |min_frequencies| and no more than |max_frequencies|). After all
93 // previously seen frequencies have been requested, each |InitiateScan|
94 // scans the next |max_frequencies| until all |available_frequencies| have
95 // been exhausted.
96 //
97 // If a scan request to the kernel returns an error, |on_scan_failed| is
98 // called. The caller can reissue the scan by calling |ReInitiateScan| or
99 // abort the scan session by deleting the |ScanSession| object.
100 ScanSession(NetlinkManager *netlink_manager,
101 EventDispatcher *dispatcher,
102 const WiFiProvider::FrequencyCountList &previous_frequencies,
103 const std::set<uint16_t> &available_frequencies,
104 uint32_t ifindex,
105 const FractionList &fractions,
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -0700106 size_t min_frequencies,
107 size_t max_frequencies,
Wade Guthrief22681f2013-05-31 11:46:31 -0700108 OnScanFailed on_scan_failed,
109 Metrics *metrics);
Wade Guthriea60a11c2013-04-12 17:47:34 -0700110
111 virtual ~ScanSession();
112
113 // Returns true if |ScanSession| contains unscanned frequencies.
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -0700114 virtual bool HasMoreFrequencies() const;
Wade Guthriea60a11c2013-04-12 17:47:34 -0700115
Wade Guthrieb9c3feb2013-04-25 16:31:19 -0700116 // Adds an SSID to the list of things for which to scan. Useful for hidden
117 // SSIDs.
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -0700118 virtual void AddSsid(const ByteString &ssid);
Wade Guthrieb9c3feb2013-04-25 16:31:19 -0700119
120 // Start a wifi scan of the next set of frequencies (derived from the
121 // constructor's parameters) after saving those frequencies for the potential
122 // need to reinitiate a scan.
123 virtual void InitiateScan();
124
125 // Re-issues the previous scan (i.e., it uses the same frequency list as the
126 // previous scan). Other classes may use this when |on_scan_failed| is
127 // called. Called by |OnTriggerScanResponse| when the previous attempt to do
128 // a scan fails.
129 void ReInitiateScan();
130
131 private:
132 friend class ScanSessionTest;
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -0700133 friend class WiFiObjectTest; // OnTriggerScanResponse.
134 FRIEND_TEST(ScanSessionTest, EBusy);
135 FRIEND_TEST(ScanSessionTest, OnError);
136 FRIEND_TEST(ScanSessionTest, OnTriggerScanResponse);
137
Wade Guthrieb9c3feb2013-04-25 16:31:19 -0700138 // Milliseconds to wait before retrying a failed scan.
139 static const uint64_t kScanRetryDelayMilliseconds;
140 // Number of times to retry a failed scan before giving up and calling
141 // |on_scan_failed_|.
142 static const size_t kScanRetryCount;
143
144 // Assists with sorting the |previous_frequencies| passed to the
145 // constructor.
146 static bool CompareFrequencyCount(const WiFiProvider::FrequencyCount &first,
147 const WiFiProvider::FrequencyCount &second);
148
Wade Guthriea60a11c2013-04-12 17:47:34 -0700149 // |GetScanFrequencies| gets the next set of WiFi scan frequencies. Returns
150 // at least |min_frequencies| (unless fewer frequencies remain from previous
151 // calls) and no more than |max_frequencies|. Inside these constraints,
152 // |GetScanFrequencies| tries to return at least the number of frequencies
153 // required to reach the connection fraction |scan_fraction| out of the total
154 // number of previous connections. For example, the first call requesting
155 // 33.3% will return the minimum number frequencies that add up to _at least_
156 // the 33.3rd percentile of frequencies to which we've successfully connected
157 // in the past. The next call of 33.3% returns the minimum number of
158 // frequencies required so that the total of the frequencies returned are _at
159 // least_ the 66.6th percentile of the frequencies to which we've successfully
160 // connected.
161 //
162 // For example, say we've connected to 3 frequencies before:
163 // freq a,count=10; freq b,count=5; freq c,count=5.
164 //
165 // GetScanFrequencies(.50,2,10) // Returns a & b (|a| reaches %ile but |b| is
166 // // required to meet the minimum).
167 // GetScanFrequencies(.51,2,10) // Returns c & 9 frequencies from the list
168 // // of frequencies to which we've never
169 // // connected.
170 virtual std::vector<uint16_t> GetScanFrequencies(float scan_fraction,
171 size_t min_frequencies,
172 size_t max_frequencies);
173
Wade Guthrieb9c3feb2013-04-25 16:31:19 -0700174 // Does the real work of initiating a scan by sending an
175 // NL80211_CMD_TRIGGER_SCAN message to the kernel and installing a handler for
176 // any response (which only happens in the error case).
177 void DoScan(const std::vector<uint16_t> &scan_frequencies);
Wade Guthriea60a11c2013-04-12 17:47:34 -0700178
Wade Guthrieb9c3feb2013-04-25 16:31:19 -0700179 // Handles any unicast response to NL80211_CMD_TRIGGER_SCAN (which is,
180 // likely, an error -- when things work, we get an
181 // NL80211_CMD_NEW_SCAN_RESULTS broadcast message).
Wade Guthrie7347bf22013-04-30 11:21:51 -0700182 void OnTriggerScanResponse(const Nl80211Message &message);
Wade Guthrie84db7ce2013-06-12 11:40:49 -0700183 void OnTriggerScanErrorResponse(NetlinkManager::AuxilliaryMessageType type,
184 const NetlinkMessage *netlink_message);
Wade Guthrief22681f2013-05-31 11:46:31 -0700185 void ReportEbusyTime(int log_level);
186
Wade Guthrie7b310a12013-05-28 15:37:13 -0700187 // Logs the results of the scan.
188 void ReportResults(int log_level);
189
Wade Guthrieb9c3feb2013-04-25 16:31:19 -0700190 base::WeakPtrFactory<ScanSession> weak_ptr_factory_;
191
192 NetlinkManager *netlink_manager_;
193 EventDispatcher *dispatcher_;
Wade Guthriea60a11c2013-04-12 17:47:34 -0700194
195 // List of frequencies, sorted by the number of successful connections for
196 // each frequency.
197 WiFiProvider::FrequencyCountList frequency_list_;
198 size_t total_connections_;
199 size_t total_connects_provided_;
200 float total_fraction_wanted_;
Wade Guthrieb9c3feb2013-04-25 16:31:19 -0700201 std::vector<uint16_t> current_scan_frequencies_;
202 uint32_t wifi_interface_index_;
203 std::set<ByteString, bool(*)(const ByteString &, const ByteString &)> ssids_;
204 FractionList fractions_;
205 size_t min_frequencies_;
206 size_t max_frequencies_;
207 OnScanFailed on_scan_failed_;
208 size_t scan_tries_left_;
Wade Guthrie7b310a12013-05-28 15:37:13 -0700209 bool found_error_;
Wade Guthriea60a11c2013-04-12 17:47:34 -0700210
Wade Guthrief22681f2013-05-31 11:46:31 -0700211 // Statistics gathering.
Wade Guthrie7b310a12013-05-28 15:37:13 -0700212 size_t original_frequency_count_;
Wade Guthrief22681f2013-05-31 11:46:31 -0700213 chromeos_metrics::Timer ebusy_timer_;
214 Metrics *metrics_;
215
Wade Guthriea60a11c2013-04-12 17:47:34 -0700216 DISALLOW_COPY_AND_ASSIGN(ScanSession);
217};
218
219} // namespace shill.
220
221#endif // SHILL_SCAN_SESSION_H_