Bug 1568126 - Part 1: Use the contextual WalkerFront in _hideHighlighterIfDeadNode...
[gecko.git] / netwerk / wifi / win_wifiScanner.cpp
blobcc42cd414c7a9c392d7635e7b38790d84bb7a191
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsWifiAccessPoint.h"
6 #include "win_wifiScanner.h"
8 // Moz headers (alphabetical)
9 #include "win_wlanLibrary.h"
11 #define DOT11_BSS_TYPE_UNUSED static_cast<DOT11_BSS_TYPE>(0)
13 class InterfaceScanCallbackData {
14 public:
15 explicit InterfaceScanCallbackData(uint32_t numInterfaces)
16 : mCurrentlyScanningInterfaces(numInterfaces) {
17 mAllInterfacesDoneScanningEvent =
18 ::CreateEvent(nullptr, // null security
19 TRUE, // manual reset event
20 FALSE, // initially nonsignaled
21 nullptr); // not named
22 MOZ_ASSERT(NULL != mAllInterfacesDoneScanningEvent);
25 ~InterfaceScanCallbackData() {
26 ::CloseHandle(mAllInterfacesDoneScanningEvent);
29 void OnInterfaceScanComplete() {
30 uint32_t val = ::InterlockedDecrement(&mCurrentlyScanningInterfaces);
31 if (!val) {
32 ::SetEvent(mAllInterfacesDoneScanningEvent);
36 void WaitForAllInterfacesToFinishScanning(uint32_t msToWait) {
37 ::WaitForSingleObject(mAllInterfacesDoneScanningEvent, msToWait);
40 private:
41 volatile uint32_t mCurrentlyScanningInterfaces;
42 HANDLE mAllInterfacesDoneScanningEvent;
45 static void WINAPI OnScanComplete(PWLAN_NOTIFICATION_DATA data, PVOID context) {
46 if (WLAN_NOTIFICATION_SOURCE_ACM != data->NotificationSource) {
47 return;
50 if (wlan_notification_acm_scan_complete != data->NotificationCode &&
51 wlan_notification_acm_scan_fail != data->NotificationCode) {
52 return;
55 InterfaceScanCallbackData* cbData =
56 reinterpret_cast<InterfaceScanCallbackData*>(context);
57 cbData->OnInterfaceScanComplete();
60 WinWifiScanner::WinWifiScanner() {
61 // NOTE: We assume that, if we were unable to load the WLAN library when
62 // we initially tried, we will not be able to load it in the future.
63 // Technically, on Windows XP SP2, a user could install the redistributable
64 // and make our assumption incorrect. We opt to avoid making a bunch of
65 // spurious LoadLibrary calls in the common case rather than load the
66 // WLAN API in the edge case.
67 mWlanLibrary = WinWLANLibrary::Load();
68 if (!mWlanLibrary) {
69 NS_WARNING("Could not initialize Windows Wi-Fi scanner");
73 WinWifiScanner::~WinWifiScanner() {}
75 nsresult WinWifiScanner::GetAccessPointsFromWLAN(
76 nsCOMArray<nsWifiAccessPoint>& accessPoints) {
77 accessPoints.Clear();
79 // NOTE: We do not try to load the WLAN library if we previously failed
80 // to load it. See the note in WinWifiScanner constructor
81 if (!mWlanLibrary) {
82 return NS_ERROR_NOT_AVAILABLE;
85 // Get the list of interfaces. WlanEnumInterfaces allocates interface_list.
86 WLAN_INTERFACE_INFO_LIST* interface_list = nullptr;
87 if (ERROR_SUCCESS !=
88 (*mWlanLibrary->GetWlanEnumInterfacesPtr())(mWlanLibrary->GetWLANHandle(),
89 nullptr, &interface_list)) {
90 return NS_ERROR_FAILURE;
93 // This ensures we call WlanFreeMemory on interface_list
94 ScopedWLANObject scopedInterfaceList(mWlanLibrary, interface_list);
96 if (!interface_list->dwNumberOfItems) {
97 return NS_OK;
100 InterfaceScanCallbackData cbData(interface_list->dwNumberOfItems);
102 DWORD wlanNotifySource;
103 if (ERROR_SUCCESS != (*mWlanLibrary->GetWlanRegisterNotificationPtr())(
104 mWlanLibrary->GetWLANHandle(),
105 WLAN_NOTIFICATION_SOURCE_ACM, TRUE,
106 (WLAN_NOTIFICATION_CALLBACK)OnScanComplete, &cbData,
107 NULL, &wlanNotifySource)) {
108 return NS_ERROR_FAILURE;
111 // Go through the list of interfaces and call `WlanScan` on each
112 for (unsigned int i = 0; i < interface_list->dwNumberOfItems; ++i) {
113 if (ERROR_SUCCESS != (*mWlanLibrary->GetWlanScanPtr())(
114 mWlanLibrary->GetWLANHandle(),
115 &interface_list->InterfaceInfo[i].InterfaceGuid,
116 NULL, NULL, NULL)) {
117 cbData.OnInterfaceScanComplete();
121 // From the MSDN documentation:
122 // "Wireless network drivers that meet Windows logo requirements are
123 // required to complete a WlanScan function request in 4 seconds"
124 cbData.WaitForAllInterfacesToFinishScanning(5000);
126 // Unregister for the notifications. The documentation mentions that,
127 // if a callback is currently running, this will wait for the callback
128 // to complete.
129 (*mWlanLibrary->GetWlanRegisterNotificationPtr())(
130 mWlanLibrary->GetWLANHandle(), WLAN_NOTIFICATION_SOURCE_NONE, TRUE, NULL,
131 NULL, NULL, &wlanNotifySource);
133 // Go through the list of interfaces and get the data for each.
134 for (uint32_t i = 0; i < interface_list->dwNumberOfItems; ++i) {
135 WLAN_BSS_LIST* bss_list;
136 if (ERROR_SUCCESS != (*mWlanLibrary->GetWlanGetNetworkBssListPtr())(
137 mWlanLibrary->GetWLANHandle(),
138 &interface_list->InterfaceInfo[i].InterfaceGuid,
139 nullptr, // Use all SSIDs.
140 DOT11_BSS_TYPE_UNUSED,
141 false, // bSecurityEnabled - unused
142 nullptr, // reserved
143 &bss_list)) {
144 continue;
147 // This ensures we call WlanFreeMemory on bss_list
148 ScopedWLANObject scopedBssList(mWlanLibrary, bss_list);
150 // Store each discovered access point in our outparam
151 for (int j = 0; j < static_cast<int>(bss_list->dwNumberOfItems); ++j) {
152 nsWifiAccessPoint* ap = new nsWifiAccessPoint();
153 if (!ap) {
154 continue;
157 const WLAN_BSS_ENTRY bss_entry = bss_list->wlanBssEntries[j];
158 ap->setMac(bss_entry.dot11Bssid);
159 ap->setSignal(bss_entry.lRssi);
160 ap->setSSID(reinterpret_cast<char const*>(bss_entry.dot11Ssid.ucSSID),
161 bss_entry.dot11Ssid.uSSIDLength);
163 accessPoints.AppendObject(ap);
167 return NS_OK;