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