OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 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. | |
4 | |
5 #include "chrome/utility/wifi/wifi_service.h" | |
6 | |
7 #include <iphlpapi.h> | |
8 #include <objbase.h> | |
9 #include <wlanapi.h> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/memory/ref_counted.h" | |
13 #include "base/message_loop/message_loop.h" | |
14 #include "base/strings/string16.h" | |
15 #include "base/strings/string_util.h" | |
16 #include "base/strings/utf_string_conversions.h" | |
17 #include "components/onc/onc_constants.h" | |
18 | |
19 namespace wifi { | |
Jói
2013/10/19 21:14:45
I believe in the src/chrome folder we're mostly ge
mef
2013/10/21 15:37:16
Interesting. I'll check the component idea. Per di
Jói
2013/10/21 16:44:03
If there are no plans to use it other than for ext
mef
2013/10/21 19:42:00
Done. If you don't have strong objections I'd keep
| |
20 | |
21 // Implementation of WiFiService for Windows. | |
22 class WiFiServiceImpl : public WiFiService, base::NonThreadSafe { | |
23 public: | |
24 WiFiServiceImpl(); | |
25 virtual ~WiFiServiceImpl(); | |
26 | |
27 // WiFiService interface implementation. | |
28 | |
29 virtual void GetProperties(const std::string& network_guid, | |
30 const NetworkPropertiesCallback& callback, | |
31 const ErrorCallback& error_callback) OVERRIDE; | |
32 | |
33 virtual void GetState(const std::string& network_guid, | |
34 const NetworkPropertiesCallback& callback, | |
35 const ErrorCallback& error_callback) OVERRIDE; | |
36 | |
37 virtual void GetManagedProperties( | |
38 const std::string& network_guid, | |
39 const DictionaryResultCallback& callback, | |
40 const ErrorCallback& error_callback) OVERRIDE; | |
41 | |
42 virtual void SetProperties(const std::string& network_guid, | |
43 const base::DictionaryValue& properties, | |
44 const StringResultCallback& callback, | |
45 const ErrorCallback& error_callback) OVERRIDE; | |
46 | |
47 virtual void GetVisibleNetworks(const NetworkListCallback& callback, | |
48 const ErrorCallback& error_callback) OVERRIDE; | |
49 | |
50 virtual void RequestNetworkScan() OVERRIDE; | |
51 | |
52 virtual void StartConnect(const std::string& network_guid, | |
53 const StringResultCallback& callback, | |
54 const ErrorCallback& error_callback) OVERRIDE; | |
55 | |
56 virtual void StartDisconnect(const std::string& network_guid, | |
57 const StringResultCallback& callback, | |
58 const ErrorCallback& error_callback) OVERRIDE; | |
59 | |
60 virtual void SetNetworksChangedObserver( | |
61 const NetworkGuidListCallback& observer) OVERRIDE; | |
62 | |
63 virtual void SetNetworkListChangedObserver( | |
64 const NetworkGuidListCallback& observer) OVERRIDE; | |
65 | |
66 private: | |
67 // Static callback for Windows WLAN_NOTIFICATION. Calls OnWlanNotification | |
68 // on WiFiServiceImpl passed back as |context|. | |
69 static void __stdcall OnWlanNotificationCallback( | |
70 PWLAN_NOTIFICATION_DATA wlan_notification_data, | |
71 PVOID context); | |
72 | |
73 // Callback for Windows WLAN_NOTIFICATION. Called on random thread from | |
74 // OnWlanNotificationCallback. Handles network connectivity and scan complete | |
75 // notification and posts tasks to main thread. | |
76 void OnWlanNotification(PWLAN_NOTIFICATION_DATA wlan_notification_data); | |
77 | |
78 // Handles NetworkScanComplete notification on main thread. Sends | |
79 // |NetworkListChanged| event with new list of visible networks. | |
80 void OnNetworkScanCompleteOnMainThread(); | |
81 | |
82 // Wait up to |kMaxAttempts| with |kAttemptDelayMs| delay for connection | |
83 // to network with |network_guid|. Reset DHCP and Notify that |NetworkChanged| | |
84 // upon success. | |
85 void WaitForNetworkConnect(const std::string& network_guid, int attempt); | |
86 | |
87 // Check |error_code| and if is not |ERROR_SUCCESS|, then run |error_callback| | |
88 // with |error_name|. | |
89 bool CheckError(const ErrorCallback& error_callback, | |
90 const std::string& error_name, | |
91 DWORD error_code) const; | |
92 | |
93 // Return |iterator| to network identified by |network_guid| in |networks| | |
94 // list. | |
95 NetworkList::const_iterator FindNetwork( | |
96 const NetworkList& networks, | |
97 const std::string& network_guid) const; | |
98 | |
99 // Save currently connected network profile and return its | |
100 // |connected_network_guid|, so it can be re-connected later. | |
101 DWORD SaveCurrentConnectedNetwork(std::string* connected_network_guid); | |
102 | |
103 // Sort networks, so connected/connecting is up front, then by type: | |
104 // Ethernet, WiFi, Cellular, VPN | |
105 static void SortNetworks(NetworkList* networks); | |
106 | |
107 // Open a WLAN client handle, register for WLAN notifications. | |
108 DWORD OpenClientHandle(); | |
109 | |
110 // Reset DHCP on wireless adapter to speed up reconnect after chromecast | |
Jói
2013/10/19 21:14:45
Is this code specific to Chromecast? If not, sugge
mef
2013/10/21 15:37:16
Done.
| |
111 // device reset | |
112 DWORD ResetDHCP(); | |
Jói
2013/10/19 21:14:45
Here you upper-case DHCP; in OnWlanNotification an
mef
2013/10/21 15:37:16
Done. I've chosen upper-case.
| |
113 | |
114 // Find |adapter_index_map| by |interface_guid| for DHCP reset. | |
115 DWORD FindAdapterIndexMapByGuid(const GUID& interface_guid, | |
116 IP_ADAPTER_INDEX_MAP* adapter_index_map); | |
117 | |
118 // Ensure that |client_| handle is initialized. | |
119 DWORD EnsureInitialized(); | |
120 | |
121 // Close |client_| handle if it is open. | |
122 DWORD CloseClientHandle(); | |
123 | |
124 // Get |profile_name| from unique |network_guid|. | |
125 base::string16 ProfileNameFromGuid(const std::string& network_guid) const { | |
126 return base::UTF8ToUTF16(network_guid); | |
127 } | |
128 | |
129 // Get |dot11Ssid| from unique |network_guid|. | |
130 DOT11_SSID SsidFromGuid(const std::string& network_guid) const; | |
131 | |
132 // Get unique |network_guid| string based on |dot11Ssid|. | |
133 std::string GuidFromSsid(const DOT11_SSID& dot11Ssid) const { | |
afontan
2013/10/21 16:55:23
dot11Ssid is not a GUID and it is not unique. You
mef
2013/10/21 19:42:00
I could make it an interface-ssid-bssid combinatio
afontan
2013/10/21 20:51:02
Correct. The 5GHz/2.4GHz with same SSID is the sce
mef
2013/10/24 23:44:47
Done. Per discussion with tbarzic@ we'll keep the
| |
134 return std::string(reinterpret_cast<const char*>(dot11Ssid.ucSSID), | |
135 dot11Ssid.uSSIDLength); | |
136 } | |
137 | |
138 // Get network |ssid| string based on |wlan|. | |
139 std::string SsidFromWlan(const WLAN_AVAILABLE_NETWORK& wlan) const { | |
140 return GuidFromSsid(wlan.dot11Ssid); | |
141 } | |
142 | |
143 // Get unique |network_guid| string based on |wlan|. | |
144 std::string GuidFromWlan(const WLAN_AVAILABLE_NETWORK& wlan) const { | |
afontan
2013/10/21 16:55:23
ditto.
mef
2013/10/24 23:44:47
Done. Same as GUIDFromSSID().
| |
145 return SsidFromWlan(wlan); | |
146 } | |
147 | |
148 // Deduce |onc::wifi| security from |alg|. | |
149 std::string SecurityFromDot11AuthAlg(DOT11_AUTH_ALGORITHM alg) const; | |
150 | |
151 // Populate |properties| based on |wlan| and its corresponding bss info from | |
152 // |wlan_bss_list|. | |
153 void NetworkPropertiesFromAvailableNetwork(const WLAN_AVAILABLE_NETWORK& wlan, | |
154 const WLAN_BSS_LIST& wlan_bss_list, | |
155 NetworkProperties* properties); | |
156 // Get the list of visible wireless networks. | |
157 DWORD GetVisibleNetworkList(NetworkList* network_list); | |
158 | |
159 // Find currently connected network if any. Populate |connected_network_guid| | |
160 // on success. | |
161 DWORD FindConnectedNetwork(std::string* connected_network_guid); | |
162 | |
163 // Connect to network |network_guid| using previosly stored profile if exists, | |
164 // or just network sid. | |
165 DWORD Connect(const std::string& network_guid); | |
166 | |
167 // Disconnect from currently connected network if any. | |
168 DWORD Disconnect(); | |
169 | |
170 // Save temporary wireless profile for |network_guid|. | |
171 DWORD SaveTempProfile(const std::string& network_guid); | |
172 | |
173 // Get previously stored |profile_xml| for |network_guid|. | |
174 DWORD GetProfile(const std::string& network_guid, std::string* profile_xml); | |
175 | |
176 // Return true if there is previously stored profile xml for |network_guid|. | |
177 bool HaveProfile(const std::string& network_guid); | |
178 | |
179 // Notify |network_list_changed_observer_| that list of visible networks has | |
180 // changed to |networks|. | |
181 void NotifyNetworkListChanged(const NetworkList& networks); | |
182 | |
183 // Notify |networks_changed_observer_| that network |network_guid| status has | |
184 // changed. | |
185 void NotifyNetworkChanged(const std::string& network_guid); | |
186 | |
187 // Wlan Service Handle. | |
Jói
2013/10/19 21:14:45
Title case seems unnecessary, here and next couple
mef
2013/10/21 15:37:16
Done.
| |
188 HANDLE client_; | |
189 // Wlan Interface Guid. | |
Jói
2013/10/19 21:14:45
A better comment might be "GUID of the currently c
mef
2013/10/21 15:37:16
Done.
| |
190 GUID interface_guid_; | |
191 // Preserved Wlan Profile Xml. | |
192 std::map<std::string, std::string> saved_profiles_xml_; | |
193 // Observer to get notified when network(s) have changed (e.g. connect). | |
194 NetworkGuidListCallback networks_changed_observer_; | |
195 // Observer to get notified when network list has changed (scan complete). | |
196 NetworkGuidListCallback network_list_changed_observer_; | |
197 // Task runner to post tasks on main thread. | |
198 scoped_refptr<base::TaskRunner> task_runner_; | |
199 // If |false|, then |networks_changed_observer_| is not notified. | |
200 bool enable_notify_network_changed_; | |
201 // Number of attempts to check that network has connected successfully. | |
202 static const int kMaxAttempts = 100; | |
203 // Delay between attempts to check that network has connected successfully. | |
204 static const int kAttemptDelayMs = 100; | |
205 // Delay after DHCP Renew to allow IP address to be acquired. | |
206 static const int kDhcpRenewDelayMs = 5000; | |
207 | |
208 DISALLOW_COPY_AND_ASSIGN(WiFiServiceImpl); | |
209 }; | |
210 | |
211 WiFiServiceImpl::WiFiServiceImpl() | |
212 : client_(NULL), enable_notify_network_changed_(true) {} | |
213 | |
214 WiFiServiceImpl::~WiFiServiceImpl() { CloseClientHandle(); } | |
215 | |
216 void WiFiServiceImpl::GetProperties(const std::string& network_guid, | |
217 const NetworkPropertiesCallback& callback, | |
Jói
2013/10/19 21:14:45
I'm assuming the interface here and other places i
mef
2013/10/21 15:37:16
Yes, AFAIR Mac OS X WiFiFoundation uses callbacks
Jói
2013/10/21 16:44:03
OK, fine by me, just checking.
| |
218 const ErrorCallback& error_callback) { | |
219 DWORD error = EnsureInitialized(); | |
220 if (error == ERROR_SUCCESS) { | |
221 NetworkList network_list; | |
222 error = GetVisibleNetworkList(&network_list); | |
223 if (error == ERROR_SUCCESS && !network_list.empty()) { | |
224 NetworkList::const_iterator it = FindNetwork(network_list, network_guid); | |
225 if (it != network_list.end()) { | |
226 DLOG(INFO) << "Get Properties: " << network_guid << ":" | |
227 << it->connection_state; | |
228 callback.Run(network_guid, *it); | |
Jói
2013/10/19 21:14:45
Could return right after this, no need to CheckErr
mef
2013/10/21 15:37:16
Done.
| |
229 } else { | |
230 error = ERROR_NOT_FOUND; | |
231 } | |
232 } | |
233 } | |
234 | |
235 CheckError(error_callback, "Error.DBusFailed", error); | |
236 } | |
237 | |
238 void WiFiServiceImpl::GetState(const std::string& network_guid, | |
239 const NetworkPropertiesCallback& callback, | |
240 const ErrorCallback& error_callback) {} | |
Jói
2013/10/19 21:14:45
Might want to comment here and GetManagedPropertie
mef
2013/10/21 15:37:16
Done.
| |
241 | |
242 void WiFiServiceImpl::GetManagedProperties( | |
243 const std::string& network_guid, | |
244 const DictionaryResultCallback& callback, | |
245 const ErrorCallback& error_callback) {} | |
246 | |
247 void WiFiServiceImpl::SetProperties(const std::string& network_guid, | |
248 const base::DictionaryValue& properties, | |
249 const StringResultCallback& callback, | |
250 const ErrorCallback& error_callback) {} | |
251 | |
252 void WiFiServiceImpl::GetVisibleNetworks(const NetworkListCallback& callback, | |
253 const ErrorCallback& error_callback) { | |
254 DWORD error = EnsureInitialized(); | |
255 | |
256 if (error == ERROR_SUCCESS) { | |
257 NetworkList network_list; | |
258 error = GetVisibleNetworkList(&network_list); | |
259 if (error == ERROR_SUCCESS && !network_list.empty()) { | |
260 SortNetworks(&network_list); | |
afontan
2013/10/21 16:55:23
I would have expected the API to retrieve the netw
mef
2013/10/21 19:42:00
Is it something that could block for considerable
| |
261 callback.Run(network_list); | |
Jói
2013/10/19 21:14:45
Could return here, no need to CheckError.
This pr
mef
2013/10/21 15:37:16
Done.
| |
262 } | |
263 } | |
264 | |
265 CheckError(error_callback, "Error.DBusFailed", error); | |
266 } | |
267 | |
268 void WiFiServiceImpl::RequestNetworkScan() { | |
269 DWORD error = EnsureInitialized(); | |
270 if (error == ERROR_SUCCESS) { | |
271 WlanScan(client_, &interface_guid_, NULL, NULL, NULL); | |
272 } | |
273 } | |
274 | |
275 void WiFiServiceImpl::StartConnect(const std::string& network_guid, | |
276 const StringResultCallback& callback, | |
277 const ErrorCallback& error_callback) { | |
278 DLOG(INFO) << "Start Connect: " << network_guid; | |
279 DWORD error = EnsureInitialized(); | |
280 if (error == ERROR_SUCCESS) { | |
281 std::string connected_network_guid; | |
282 error = SaveCurrentConnectedNetwork(&connected_network_guid); | |
283 if (error == ERROR_SUCCESS) { | |
284 // Connect only if network |network_guid| is not connected already. | |
285 if (network_guid != connected_network_guid) | |
286 error = Connect(network_guid); | |
afontan
2013/10/21 16:55:23
One thing we were asked is to avoid the network lo
mef
2013/10/21 19:42:00
Cool, Will do.
mef
2013/10/22 20:06:01
Done.
| |
287 if (error == ERROR_SUCCESS) { | |
288 callback.Run(network_guid); | |
Jói
2013/10/19 21:14:45
Just checking: Are you sure you want to run this b
mef
2013/10/21 15:37:16
I think so. Logically caller is start the Connect,
Jói
2013/10/21 16:44:03
OK.
| |
289 // Notify that previously connected network has changed. | |
290 NotifyNetworkChanged(connected_network_guid); | |
291 // Start waiting for network connection state change. | |
292 if (!networks_changed_observer_.is_null()) { | |
293 // Disable automatic network change notifications. | |
294 enable_notify_network_changed_ = false; | |
295 WaitForNetworkConnect(network_guid, 0); | |
296 } | |
297 } | |
298 } | |
299 } | |
300 CheckError(error_callback, "Error.DBusFailed", error); | |
301 } | |
302 | |
303 void WiFiServiceImpl::StartDisconnect(const std::string& network_guid, | |
304 const StringResultCallback& callback, | |
305 const ErrorCallback& error_callback) { | |
306 DLOG(INFO) << "Start Disconnect: " << network_guid; | |
307 DWORD error = EnsureInitialized(); | |
308 if (error == ERROR_SUCCESS) { | |
309 std::string connected_network_guid; | |
310 error = SaveCurrentConnectedNetwork(&connected_network_guid); | |
311 if (error == ERROR_SUCCESS && network_guid == connected_network_guid) { | |
312 error = Disconnect(); | |
313 if (error == ERROR_SUCCESS) { | |
314 NotifyNetworkChanged(network_guid); | |
315 callback.Run(network_guid); | |
316 } | |
317 } | |
318 } | |
319 CheckError(error_callback, "Error.DBusFailed", error); | |
Jói
2013/10/19 21:14:45
Error.DBusFailed is a bit of a weird error for Win
mef
2013/10/21 15:37:16
Done. Yes, it was a ChromeOS legacy, but it doesn'
| |
320 } | |
321 | |
322 void WiFiServiceImpl::SetNetworksChangedObserver( | |
323 const NetworkGuidListCallback& observer) { | |
324 networks_changed_observer_ = observer; | |
325 } | |
326 | |
327 void WiFiServiceImpl::SetNetworkListChangedObserver( | |
328 const NetworkGuidListCallback& observer) { | |
329 network_list_changed_observer_ = observer; | |
330 } | |
331 | |
332 void WiFiServiceImpl::OnWlanNotificationCallback( | |
333 PWLAN_NOTIFICATION_DATA wlan_notification_data, | |
334 PVOID context) { | |
335 WiFiServiceImpl* service = reinterpret_cast<WiFiServiceImpl*>(context); | |
336 service->OnWlanNotification(wlan_notification_data); | |
337 } | |
338 | |
339 void WiFiServiceImpl::OnWlanNotification( | |
340 PWLAN_NOTIFICATION_DATA wlan_notification_data) { | |
341 PWLAN_CONNECTION_NOTIFICATION_DATA wlan_connection_data = | |
342 reinterpret_cast<PWLAN_CONNECTION_NOTIFICATION_DATA>( | |
343 wlan_notification_data->pData); | |
344 | |
345 switch (wlan_notification_data->NotificationCode) { | |
346 case wlan_notification_acm_disconnected: | |
347 case wlan_notification_acm_connection_complete: | |
348 case wlan_notification_acm_connection_attempt_fail: | |
349 task_runner_->PostTask( | |
350 FROM_HERE, | |
351 base::Bind(&WiFiServiceImpl::NotifyNetworkChanged, | |
352 base::Unretained(this), | |
353 GuidFromSsid(wlan_connection_data->dot11Ssid))); | |
354 break; | |
355 case wlan_notification_acm_scan_complete: | |
356 task_runner_->PostTask( | |
357 FROM_HERE, | |
358 base::Bind(&WiFiServiceImpl::OnNetworkScanCompleteOnMainThread, | |
359 base::Unretained(this))); | |
360 break; | |
361 } | |
Jói
2013/10/19 21:14:45
I would add a default: case that DCHECKs.
mef
2013/10/21 15:37:16
I can't, there are more notification types that we
Jói
2013/10/21 16:44:03
If you get one of the other notifications, then yo
mef
2013/10/21 19:42:00
Done.
| |
362 } | |
363 | |
364 void WiFiServiceImpl::OnNetworkScanCompleteOnMainThread() { | |
365 NetworkList networks; | |
366 DWORD error = GetVisibleNetworkList(&networks); | |
Jói
2013/10/19 21:14:45
Why do you need to do this before notifying that t
mef
2013/10/21 15:37:16
Done. Added a comment. Not sure what would a good
Jói
2013/10/21 16:44:03
DCHECK seems right if you expect this to always su
mef
2013/10/21 19:42:00
Done.
| |
367 if (error == ERROR_SUCCESS) | |
368 NotifyNetworkListChanged(networks); | |
369 } | |
370 | |
371 void WiFiServiceImpl::WaitForNetworkConnect(const std::string& network_guid, | |
372 int attempt) { | |
373 if (attempt > kMaxAttempts) { | |
374 enable_notify_network_changed_ = true; | |
Jói
2013/10/19 21:14:45
Why is this is set to true when max attempts have
mef
2013/10/21 15:37:16
At this point we don't expect this network to get
| |
375 return; | |
376 } | |
377 std::string connected_network_guid; | |
378 DWORD error = FindConnectedNetwork(&connected_network_guid); | |
379 if (network_guid == connected_network_guid) { | |
380 DLOG(INFO) << "WiFi Connected, Reset DHCP: " << network_guid; | |
381 enable_notify_network_changed_ = true; | |
382 // Reset DHCP to speed up the connection after Chromekey factory reset. | |
Jói
2013/10/19 21:14:45
Same question on whether code is specific to Chrom
mef
2013/10/21 15:37:16
Done. Added better comment.
| |
383 error = ResetDHCP(); | |
384 if (error == ERROR_SUCCESS) { | |
385 base::MessageLoop::current()->PostDelayedTask( | |
Jói
2013/10/19 21:14:45
Why is this delayed if resetting DHCP was successf
mef
2013/10/21 15:37:16
I've added comment, but would love to change it to
Jói
2013/10/21 16:44:03
I'm not aware of a notification you could subscrib
mef
2013/10/21 19:42:00
Sounds good, I'll try to find appropriate API.
mef
2013/10/22 20:06:01
Done. Upon further testing it turned that IP Addre
| |
386 FROM_HERE, | |
387 base::Bind(&WiFiServiceImpl::NotifyNetworkChanged, | |
388 base::Unretained(this), | |
389 network_guid), | |
390 base::TimeDelta::FromMilliseconds(kDhcpRenewDelayMs)); | |
391 } else { | |
392 NotifyNetworkChanged(network_guid); | |
393 } | |
394 } else { | |
395 // Continue waiting for network connection state change. | |
396 base::MessageLoop::current()->PostDelayedTask( | |
397 FROM_HERE, | |
398 base::Bind(&WiFiServiceImpl::WaitForNetworkConnect, | |
399 base::Unretained(this), | |
400 network_guid, | |
401 ++attempt), | |
402 base::TimeDelta::FromMilliseconds(kAttemptDelayMs)); | |
403 } | |
404 } | |
405 | |
406 bool WiFiServiceImpl::CheckError(const ErrorCallback& error_callback, | |
407 const std::string& error_name, | |
408 DWORD error_code) const { | |
409 if (error_code != ERROR_SUCCESS) { | |
410 DLOG(ERROR) << "WiFiService Error " << error_code << ": " << error_name; | |
411 scoped_ptr<base::DictionaryValue> error_data(new base::DictionaryValue); | |
412 error_data->SetInteger("Win32ErrorCode", error_code); | |
413 error_callback.Run(error_name, error_data.Pass()); | |
414 return true; | |
415 } | |
416 return false; | |
417 } | |
418 | |
419 WiFiService::NetworkList::const_iterator WiFiServiceImpl::FindNetwork( | |
420 const WiFiService::NetworkList& networks, | |
421 const std::string& network_guid) const { | |
422 for (NetworkList::const_iterator it = networks.begin(); it != networks.end(); | |
423 ++it) { | |
424 if (it->guid == network_guid) | |
425 return it; | |
426 } | |
427 return networks.end(); | |
428 } | |
429 | |
430 DWORD WiFiServiceImpl::SaveCurrentConnectedNetwork( | |
431 std::string* connected_network_guid) { | |
432 // Find currently connected network. | |
433 DWORD error = FindConnectedNetwork(connected_network_guid); | |
434 if (error == ERROR_SUCCESS && !connected_network_guid->empty()) { | |
435 if (error == ERROR_SUCCESS) { | |
436 SaveTempProfile(*connected_network_guid); | |
437 std::string profile_xml; | |
438 error = GetProfile(*connected_network_guid, &profile_xml); | |
439 if (error == ERROR_SUCCESS) { | |
440 saved_profiles_xml_[*connected_network_guid] = profile_xml; | |
441 } | |
442 } | |
443 } | |
444 return error; | |
445 } | |
446 | |
447 void WiFiServiceImpl::SortNetworks(NetworkList* networks) { | |
448 networks->sort(WiFiService::NetworkProperties::OrderByType); | |
449 } | |
450 | |
451 DWORD WiFiServiceImpl::OpenClientHandle() { | |
452 CloseClientHandle(); | |
453 | |
454 DWORD error = ERROR_SUCCESS; | |
455 DWORD service_version = 0; | |
456 | |
457 // Open a handle to the service. | |
458 error = WlanOpenHandle(WLAN_API_VERSION, NULL, &service_version, &client_); | |
459 | |
afontan
2013/10/21 16:55:23
I assume using WLAN_API_VERSION is fine (given tha
mef
2013/10/21 19:42:00
Could you elaborate on suggested change? Also, I'v
afontan
2013/10/21 20:51:02
Correct. Today we only support win 7/8. For vista
mef
2013/10/22 20:06:01
Done.
| |
460 PWLAN_INTERFACE_INFO_LIST pIntfList = NULL; | |
Jói
2013/10/19 21:14:45
pIntfList is non-compliant naming; interface_list,
mef
2013/10/21 15:37:16
Done.
| |
461 if (error == ERROR_SUCCESS) { | |
462 // Enumerate wireless interfaces. | |
463 error = WlanEnumInterfaces(client_, NULL, &pIntfList); | |
464 if (error == ERROR_SUCCESS) { | |
465 if (pIntfList != NULL && pIntfList->dwNumberOfItems != 0) { | |
466 // Remember first interface. | |
Jói
2013/10/19 21:14:45
What is special about the first interface, is this
mef
2013/10/21 15:37:16
Yes.
| |
467 interface_guid_ = pIntfList->InterfaceInfo[0].InterfaceGuid; | |
468 // Try to find connected interface. | |
Jói
2013/10/19 21:14:45
nit: find connected -> find a connected
mef
2013/10/21 15:37:16
Done.
| |
469 for (DWORD itf = 0; itf < pIntfList->dwNumberOfItems; ++itf) { | |
470 if (pIntfList->InterfaceInfo[itf].isState == | |
471 wlan_interface_state_connected) { | |
472 // Found connected interface, remember it! | |
473 interface_guid_ = pIntfList->InterfaceInfo[itf].InterfaceGuid; | |
afontan
2013/10/21 16:55:23
What if we want to setup with other wifi interface
mef
2013/10/21 19:42:00
Interesting. I suppose this loop could potentially
afontan
2013/10/21 20:51:02
The issue is that we decided to try to setup first
| |
474 break; | |
475 } | |
476 } | |
477 WlanRegisterNotification(client_, | |
478 WLAN_NOTIFICATION_SOURCE_ALL, | |
479 FALSE, | |
480 OnWlanNotificationCallback, | |
481 this, | |
482 NULL, | |
483 NULL); | |
484 } else { | |
485 error = ERROR_NOINTERFACE; | |
486 } | |
487 } | |
488 // Clean up. | |
489 if (pIntfList != NULL) | |
490 WlanFreeMemory(pIntfList); | |
491 } | |
492 return error; | |
493 } | |
494 | |
495 DWORD WiFiServiceImpl::ResetDHCP() { | |
496 IP_ADAPTER_INDEX_MAP adapter_index_map = {0}; | |
497 DWORD error = FindAdapterIndexMapByGuid(interface_guid_, &adapter_index_map); | |
498 if (error == ERROR_SUCCESS) { | |
499 error = IpReleaseAddress(&adapter_index_map); | |
500 if (error == ERROR_SUCCESS) { | |
501 error = IpRenewAddress(&adapter_index_map); | |
502 } | |
503 } | |
504 return error; | |
505 } | |
506 | |
507 DWORD WiFiServiceImpl::FindAdapterIndexMapByGuid( | |
508 const GUID& interface_guid, | |
509 IP_ADAPTER_INDEX_MAP* adapter_index_map) { | |
510 string16 guid_string; | |
511 const int kGUIDSize = 39; | |
Jói
2013/10/19 21:14:45
GUID vs. Guid -> be consistent through your code.
mef
2013/10/21 15:37:16
Done.
| |
512 ::StringFromGUID2( | |
513 interface_guid, WriteInto(&guid_string, kGUIDSize), kGUIDSize); | |
514 | |
515 ULONG buffer_length = 0; | |
516 DWORD error = GetInterfaceInfo(NULL, &buffer_length); | |
517 if (error == ERROR_INSUFFICIENT_BUFFER) { | |
518 scoped_ptr<unsigned char[]> buffer(new unsigned char[buffer_length]); | |
519 IP_INTERFACE_INFO* interface_info = | |
520 reinterpret_cast<IP_INTERFACE_INFO*>(buffer.get()); | |
521 error = GetInterfaceInfo(interface_info, &buffer_length); | |
522 if (error == ERROR_SUCCESS) { | |
523 for (int adapter = 0; adapter < interface_info->NumAdapters; ++adapter) { | |
524 if (EndsWith( | |
525 interface_info->Adapter[adapter].Name, guid_string, false)) { | |
526 *adapter_index_map = interface_info->Adapter[adapter]; | |
527 break; | |
528 } | |
529 } | |
530 } | |
531 } | |
532 return error; | |
533 } | |
534 | |
535 DWORD WiFiServiceImpl::EnsureInitialized() { | |
536 DCHECK(CalledOnValidThread()); | |
537 if (task_runner_.get() == NULL) | |
538 task_runner_ = base::MessageLoopProxy::current(); | |
539 | |
540 if (client_ != NULL) | |
Jói
2013/10/19 21:14:45
Suggest leading with this (right after the DCHECK)
mef
2013/10/21 15:37:16
Done.
| |
541 return ERROR_SUCCESS; | |
542 return OpenClientHandle(); | |
543 } | |
544 | |
545 DWORD WiFiServiceImpl::CloseClientHandle() { | |
546 DWORD error = ERROR_SUCCESS; | |
547 if (client_ != NULL) { | |
548 WlanCloseHandle(client_, NULL); | |
Jói
2013/10/19 21:14:45
should be: error = WlanCloseHandle(client_, NULL)
mef
2013/10/21 15:37:16
Done.
| |
549 client_ = NULL; | |
550 } | |
551 return error; | |
552 } | |
553 | |
554 DOT11_SSID WiFiServiceImpl::SsidFromGuid( | |
555 const std::string& network_guid) const { | |
556 DOT11_SSID ssid = {0}; | |
557 if (network_guid.length() <= DOT11_SSID_MAX_LENGTH) { | |
Jói
2013/10/19 21:14:45
Should there be e.g. a DCHECK in case the length i
mef
2013/10/21 15:37:16
Done.
| |
558 ssid.uSSIDLength = network_guid.length(); | |
559 strncpy(reinterpret_cast<char*>(ssid.ucSSID), | |
560 network_guid.c_str(), | |
561 ssid.uSSIDLength); | |
562 } | |
563 return ssid; | |
564 } | |
565 | |
566 std::string WiFiServiceImpl::SecurityFromDot11AuthAlg( | |
567 DOT11_AUTH_ALGORITHM alg) const { | |
568 // TODO(mef): Figure out correct mapping. | |
569 switch (alg) { | |
570 case DOT11_AUTH_ALGO_RSNA: | |
571 return onc::wifi::kWPA_EAP; | |
572 case DOT11_AUTH_ALGO_RSNA_PSK: | |
573 return onc::wifi::kWPA_PSK; | |
574 case DOT11_AUTH_ALGO_80211_SHARED_KEY: | |
575 return onc::wifi::kWEP_PSK; | |
576 case DOT11_AUTH_ALGO_80211_OPEN: | |
577 return onc::wifi::kNone; | |
578 default: | |
579 return onc::wifi::kWPA_EAP; | |
580 } | |
581 return onc::wifi::kWPA_EAP; | |
Jói
2013/10/19 21:14:45
This line is not needed, since you already have a
mef
2013/10/21 15:37:16
Done.
| |
582 } | |
583 | |
584 void WiFiServiceImpl::NetworkPropertiesFromAvailableNetwork( | |
585 const WLAN_AVAILABLE_NETWORK& wlan, | |
586 const WLAN_BSS_LIST& wlan_bss_list, | |
587 NetworkProperties* properties) { | |
588 if (wlan.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) { | |
589 properties->connection_state = onc::connection_state::kConnected; | |
590 } else { | |
591 properties->connection_state = onc::connection_state::kNotConnected; | |
592 } | |
593 | |
594 properties->ssid = SsidFromWlan(wlan); | |
595 properties->name = properties->ssid; | |
596 properties->guid = GuidFromWlan(wlan); | |
597 properties->type = onc::network_type::kWiFi; | |
598 | |
599 for (size_t bss = 0; bss < wlan_bss_list.dwNumberOfItems; ++bss) { | |
600 const WLAN_BSS_ENTRY& bss_entry(wlan_bss_list.wlanBssEntries[bss]); | |
601 if (bss_entry.dot11Ssid.uSSIDLength == wlan.dot11Ssid.uSSIDLength && | |
602 0 == memcmp(bss_entry.dot11Ssid.ucSSID, | |
603 wlan.dot11Ssid.ucSSID, | |
604 bss_entry.dot11Ssid.uSSIDLength)) { | |
605 if (bss_entry.ulChCenterFrequency < 3000000) | |
606 properties->frequency = kFrequency2400; | |
607 else | |
608 properties->frequency = kFrequency5000; | |
609 properties->frequency_list.push_back(properties->frequency); | |
610 properties->bssid = WiFiService::NetworkProperties::MacAddressAsString( | |
Jói
2013/10/19 21:14:45
Is the WiFiService:: prefix needed here?
mef
2013/10/21 15:37:16
Done.
| |
611 bss_entry.dot11Bssid); | |
612 } | |
613 } | |
614 properties->frequency_list.sort(); | |
615 properties->frequency_list.unique(); | |
616 properties->security = | |
617 SecurityFromDot11AuthAlg(wlan.dot11DefaultAuthAlgorithm); | |
618 properties->signal_strength = wlan.wlanSignalQuality; | |
619 } | |
620 | |
621 // Get the list of visible wireless networks | |
622 DWORD WiFiServiceImpl::GetVisibleNetworkList(NetworkList* network_list) { | |
623 DWORD error = ERROR_SUCCESS; | |
624 | |
625 if (client_ == NULL) { | |
Jói
2013/10/19 21:14:45
Should there be a NOTREACHED() here to help you ca
mef
2013/10/21 15:37:16
Done.
Jói
2013/10/21 16:44:03
You still need a NOTREACHED() in EnsureInitialized
mef
2013/10/21 19:42:00
Should I add explicit 'Initialize()' method as cur
| |
626 return ERROR_NOINTERFACE; | |
627 } | |
628 | |
629 PWLAN_AVAILABLE_NETWORK_LIST pVList = NULL; | |
Jói
2013/10/19 21:14:45
pVList -> network_list (for example)
mef
2013/10/21 15:37:16
Done.
| |
630 PWLAN_BSS_LIST pWlanBssList = NULL; | |
Jói
2013/10/19 21:14:45
pWlanBssList -> bss_list (for example)
mef
2013/10/21 15:37:16
Done.
| |
631 | |
632 error = | |
Jói
2013/10/19 21:14:45
nit: I think it would be more common to break afte
mef
2013/10/21 15:37:16
Done.
| |
633 WlanGetAvailableNetworkList(client_, &interface_guid_, 0, NULL, &pVList); | |
634 | |
635 if (error == ERROR_SUCCESS && NULL != pVList) { | |
636 error = WlanGetNetworkBssList(client_, | |
637 &interface_guid_, | |
638 NULL, | |
639 dot11_BSS_type_any, | |
640 FALSE, | |
641 NULL, | |
642 &pWlanBssList); | |
643 if (error == ERROR_SUCCESS && NULL != pWlanBssList) { | |
644 for (DWORD i = 0; i < pVList->dwNumberOfItems; ++i) { | |
645 network_list->push_back(NetworkProperties()); | |
646 NetworkPropertiesFromAvailableNetwork( | |
647 pVList->Network[i], *pWlanBssList, &network_list->back()); | |
648 } | |
649 } | |
650 } | |
651 | |
652 // clean up | |
653 if (pVList != NULL) { | |
654 WlanFreeMemory(pVList); | |
655 } | |
656 if (pWlanBssList != NULL) { | |
657 WlanFreeMemory(pWlanBssList); | |
658 } | |
659 return error; | |
660 } | |
661 | |
662 // Find currently connected network. | |
663 DWORD WiFiServiceImpl::FindConnectedNetwork( | |
664 std::string* connected_network_guid) { | |
665 DWORD error = ERROR_SUCCESS; | |
666 | |
667 if (client_ == NULL) { | |
668 return ERROR_NOINTERFACE; | |
Jói
2013/10/19 21:14:45
NOTREACHED() ?
mef
2013/10/21 15:37:16
Done.
| |
669 } | |
670 | |
671 PWLAN_AVAILABLE_NETWORK_LIST pVList = NULL; | |
Jói
2013/10/19 21:14:45
pVList -> network_list (for example)
mef
2013/10/21 15:37:16
Done.
| |
672 | |
673 error = | |
674 WlanGetAvailableNetworkList(client_, &interface_guid_, 0, NULL, &pVList); | |
Jói
2013/10/19 21:14:45
same nit re indenting; more common to indent right
mef
2013/10/21 15:37:16
Done.
afontan
2013/10/21 16:55:23
Flags is currently 0 but you should include hidden
mef
2013/10/21 19:42:00
Done. But why?
afontan
2013/10/21 20:51:02
Because the user may have configured a hidden nerw
| |
675 | |
676 if (error == ERROR_SUCCESS && NULL != pVList) { | |
677 for (DWORD i = 0; i < pVList->dwNumberOfItems; ++i) { | |
678 const WLAN_AVAILABLE_NETWORK& wlan = pVList->Network[i]; | |
679 if (wlan.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED) { | |
680 *connected_network_guid = GuidFromWlan(wlan); | |
681 break; | |
682 } | |
683 } | |
684 } | |
685 | |
686 // clean up | |
687 if (pVList != NULL) { | |
688 WlanFreeMemory(pVList); | |
689 } | |
690 | |
691 return error; | |
692 } | |
693 | |
694 DWORD WiFiServiceImpl::Connect(const std::string& network_guid) { | |
afontan
2013/10/21 16:55:23
One scenario we had to cover based on dogfooding w
mef
2013/10/21 19:42:00
Interesting. Could you elaborate on this? Currentl
tbarzic
2013/10/21 20:13:29
On ChromeOs we can't connect to a specific profile
afontan
2013/10/21 20:51:02
We get a list of band filtered Bss entries that co
mef
2013/10/24 23:44:47
Done. On separate CL.
| |
695 DWORD error = ERROR_SUCCESS; | |
696 | |
697 if (client_ == NULL) { | |
698 return ERROR_NOINTERFACE; | |
Jói
2013/10/19 21:14:45
NOTREACHED() ?
Here and all remaining "return ERR
mef
2013/10/21 15:37:16
Done.
| |
699 } | |
700 | |
701 base::string16 profile_name = ProfileNameFromGuid(network_guid); | |
702 | |
703 if (HaveProfile(network_guid)) { | |
704 WLAN_CONNECTION_PARAMETERS wlan_params = { | |
705 wlan_connection_mode_profile, profile_name.c_str(), NULL, | |
Jói
2013/10/19 21:14:45
Suggest one per line.
mef
2013/10/21 15:37:16
Done.
| |
706 NULL, dot11_BSS_type_any, 0}; | |
707 error = ::WlanConnect(client_, &interface_guid_, &wlan_params, NULL); | |
708 } else { | |
709 DOT11_SSID ssid = SsidFromGuid(network_guid); | |
710 WLAN_CONNECTION_PARAMETERS wlan_params = { | |
711 wlan_connection_mode_discovery_unsecure, NULL, &ssid, NULL, | |
Jói
2013/10/19 21:14:45
Suggest one per line.
mef
2013/10/21 15:37:16
Done.
| |
712 dot11_BSS_type_infrastructure, 0}; | |
713 error = ::WlanConnect(client_, &interface_guid_, &wlan_params, NULL); | |
Jói
2013/10/19 21:14:45
Note that per http://msdn.microsoft.com/en-us/libr
mef
2013/10/21 15:37:16
Yes. This and unsupported WlanGetNetworkBssList fu
Jói
2013/10/21 16:44:03
This needs to be fixed before check-in. According
mef
2013/10/21 19:42:00
Sounds good to be on the safe side, although from
| |
714 } | |
715 | |
716 return error; | |
717 } | |
718 | |
719 DWORD WiFiServiceImpl::Disconnect() { | |
720 DWORD error = ERROR_SUCCESS; | |
721 | |
722 if (client_ == NULL) { | |
723 return ERROR_NOINTERFACE; | |
724 } | |
725 | |
726 error = ::WlanDisconnect(client_, &interface_guid_, NULL); | |
727 return error; | |
728 } | |
729 | |
730 DWORD WiFiServiceImpl::SaveTempProfile(const std::string& network_guid) { | |
731 DWORD error = ERROR_SUCCESS; | |
732 | |
733 if (client_ == NULL) { | |
734 return ERROR_NOINTERFACE; | |
735 } | |
736 | |
737 base::string16 profile_name = ProfileNameFromGuid(network_guid); | |
738 | |
739 error = ::WlanSaveTemporaryProfile( | |
740 client_, &interface_guid_, profile_name.c_str(), NULL, 0, true, NULL); | |
Jói
2013/10/19 21:14:45
Should the profile perhaps be saved per-user? See
mef
2013/10/21 15:37:16
Done.
afontan
2013/10/21 16:55:23
In the current Chromecast implementation we save i
mef
2013/10/21 19:42:00
Done.
| |
741 return error; | |
742 } | |
743 | |
744 DWORD WiFiServiceImpl::GetProfile(const std::string& network_guid, | |
745 std::string* profile_xml) { | |
746 DWORD error = ERROR_SUCCESS; | |
747 | |
748 if (client_ == NULL) { | |
749 return ERROR_NOINTERFACE; | |
750 } | |
751 | |
752 base::string16 profile_name = ProfileNameFromGuid(network_guid); | |
753 LPWSTR str_profile_xml = NULL; | |
754 error = ::WlanGetProfile(client_, | |
Jói
2013/10/19 21:14:45
Suggest using :: in front of all the Win32 APIs yo
mef
2013/10/21 15:37:16
Done.
| |
755 &interface_guid_, | |
756 profile_name.c_str(), | |
757 NULL, | |
758 &str_profile_xml, | |
759 NULL, | |
760 NULL); | |
761 | |
762 if (error == ERROR_SUCCESS && str_profile_xml != NULL) { | |
763 *profile_xml = base::UTF16ToUTF8(str_profile_xml); | |
764 } | |
765 // clean up | |
766 if (str_profile_xml != NULL) { | |
767 WlanFreeMemory(str_profile_xml); | |
768 } | |
769 | |
770 return error; | |
771 } | |
772 | |
773 bool WiFiServiceImpl::HaveProfile(const std::string& network_guid) { | |
774 DWORD error = ERROR_SUCCESS; | |
775 std::string profile_xml; | |
776 return GetProfile(network_guid, &profile_xml) == ERROR_SUCCESS; | |
777 } | |
778 | |
779 void WiFiServiceImpl::NotifyNetworkListChanged(const NetworkList& networks) { | |
780 if (network_list_changed_observer_.is_null()) | |
781 return; | |
782 | |
783 WiFiService::NetworkGuidList current_networks; | |
784 for (WiFiService::NetworkList::const_iterator it = networks.begin(); | |
785 it != networks.end(); | |
786 ++it) { | |
787 current_networks.push_back(it->guid); | |
788 } | |
789 network_list_changed_observer_.Run(current_networks); | |
790 } | |
791 | |
792 void WiFiServiceImpl::NotifyNetworkChanged(const std::string& network_guid) { | |
793 if (enable_notify_network_changed_ && !networks_changed_observer_.is_null()) { | |
794 DLOG(INFO) << "NotifyNetworkChanged: " << network_guid; | |
795 WiFiService::NetworkGuidList changed_networks(1, network_guid); | |
Jói
2013/10/19 21:14:45
Is the WiFiService:: prefix needed here?
mef
2013/10/21 15:37:16
Done.
| |
796 networks_changed_observer_.Run(changed_networks); | |
797 } | |
798 } | |
799 | |
800 WiFiService* WiFiService::CreateService() { return new WiFiServiceImpl(); } | |
801 | |
802 } // namespace wifi | |
OLD | NEW |