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