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