Bug 1476395 - Add mochitests for the flexbox inspector sidebar. r=pbro
[gecko.git] / netwerk / wifi / win_wifiScanner.cpp
blob08c97ead7748bdcf94f2e3cc68e1e47ca3745b07
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)
18 mAllInterfacesDoneScanningEvent =
19 ::CreateEvent(nullptr, // null security
20 TRUE, // manual reset event
21 FALSE, // initially nonsignaled
22 nullptr); // not named
23 MOZ_ASSERT(NULL != mAllInterfacesDoneScanningEvent);
26 ~InterfaceScanCallbackData()
28 ::CloseHandle(mAllInterfacesDoneScanningEvent);
31 void
32 OnInterfaceScanComplete()
34 uint32_t val = ::InterlockedDecrement(&mCurrentlyScanningInterfaces);
35 if (!val) {
36 ::SetEvent(mAllInterfacesDoneScanningEvent);
40 void
41 WaitForAllInterfacesToFinishScanning(uint32_t msToWait)
43 ::WaitForSingleObject(mAllInterfacesDoneScanningEvent,
44 msToWait);
47 private:
48 volatile uint32_t mCurrentlyScanningInterfaces;
49 HANDLE mAllInterfacesDoneScanningEvent;
52 static void
53 OnScanComplete(PWLAN_NOTIFICATION_DATA data, PVOID context)
55 if (WLAN_NOTIFICATION_SOURCE_ACM != data->NotificationSource) {
56 return;
59 if (wlan_notification_acm_scan_complete != data->NotificationCode &&
60 wlan_notification_acm_scan_fail != data->NotificationCode) {
61 return;
64 InterfaceScanCallbackData* cbData =
65 reinterpret_cast<InterfaceScanCallbackData*>(context);
66 cbData->OnInterfaceScanComplete();
69 WinWifiScanner::WinWifiScanner()
71 // NOTE: We assume that, if we were unable to load the WLAN library when
72 // we initially tried, we will not be able to load it in the future.
73 // Technically, on Windows XP SP2, a user could install the redistributable
74 // and make our assumption incorrect. We opt to avoid making a bunch of
75 // spurious LoadLibrary calls in the common case rather than load the
76 // WLAN API in the edge case.
77 mWlanLibrary = WinWLANLibrary::Load();
78 if (!mWlanLibrary) {
79 NS_WARNING("Could not initialize Windows Wi-Fi scanner");
83 WinWifiScanner::~WinWifiScanner()
87 nsresult
88 WinWifiScanner::GetAccessPointsFromWLAN(nsCOMArray<nsWifiAccessPoint> &accessPoints)
90 accessPoints.Clear();
92 // NOTE: We do not try to load the WLAN library if we previously failed
93 // to load it. See the note in WinWifiScanner constructor
94 if (!mWlanLibrary) {
95 return NS_ERROR_NOT_AVAILABLE;
98 // Get the list of interfaces. WlanEnumInterfaces allocates interface_list.
99 WLAN_INTERFACE_INFO_LIST *interface_list = nullptr;
100 if (ERROR_SUCCESS !=
101 (*mWlanLibrary->GetWlanEnumInterfacesPtr())(mWlanLibrary->GetWLANHandle(),
102 nullptr,
103 &interface_list)) {
104 return NS_ERROR_FAILURE;
107 // This ensures we call WlanFreeMemory on interface_list
108 ScopedWLANObject scopedInterfaceList(mWlanLibrary, interface_list);
110 if (!interface_list->dwNumberOfItems) {
111 return NS_OK;
114 InterfaceScanCallbackData cbData(interface_list->dwNumberOfItems);
116 DWORD wlanNotifySource;
117 if (ERROR_SUCCESS !=
118 (*mWlanLibrary->GetWlanRegisterNotificationPtr())(
119 mWlanLibrary->GetWLANHandle(),
120 WLAN_NOTIFICATION_SOURCE_ACM,
121 TRUE,
122 (WLAN_NOTIFICATION_CALLBACK)OnScanComplete,
123 &cbData,
124 NULL,
125 &wlanNotifySource)) {
126 return NS_ERROR_FAILURE;
129 // Go through the list of interfaces and call `WlanScan` on each
130 for (unsigned int i = 0; i < interface_list->dwNumberOfItems; ++i) {
131 if (ERROR_SUCCESS !=
132 (*mWlanLibrary->GetWlanScanPtr())(
133 mWlanLibrary->GetWLANHandle(),
134 &interface_list->InterfaceInfo[i].InterfaceGuid,
135 NULL,
136 NULL,
137 NULL)) {
138 cbData.OnInterfaceScanComplete();
142 // From the MSDN documentation:
143 // "Wireless network drivers that meet Windows logo requirements are
144 // required to complete a WlanScan function request in 4 seconds"
145 cbData.WaitForAllInterfacesToFinishScanning(5000);
147 // Unregister for the notifications. The documentation mentions that,
148 // if a callback is currently running, this will wait for the callback
149 // to complete.
150 (*mWlanLibrary->GetWlanRegisterNotificationPtr())(
151 mWlanLibrary->GetWLANHandle(),
152 WLAN_NOTIFICATION_SOURCE_NONE,
153 TRUE,
154 NULL,
155 NULL,
156 NULL,
157 &wlanNotifySource);
159 // Go through the list of interfaces and get the data for each.
160 for (uint32_t i = 0; i < interface_list->dwNumberOfItems; ++i) {
161 WLAN_BSS_LIST *bss_list;
162 if (ERROR_SUCCESS !=
163 (*mWlanLibrary->GetWlanGetNetworkBssListPtr())(
164 mWlanLibrary->GetWLANHandle(),
165 &interface_list->InterfaceInfo[i].InterfaceGuid,
166 nullptr, // Use all SSIDs.
167 DOT11_BSS_TYPE_UNUSED,
168 false, // bSecurityEnabled - unused
169 nullptr, // reserved
170 &bss_list)) {
171 continue;
174 // This ensures we call WlanFreeMemory on bss_list
175 ScopedWLANObject scopedBssList(mWlanLibrary, bss_list);
177 // Store each discovered access point in our outparam
178 for (int j = 0; j < static_cast<int>(bss_list->dwNumberOfItems); ++j) {
179 nsWifiAccessPoint* ap = new nsWifiAccessPoint();
180 if (!ap) {
181 continue;
184 const WLAN_BSS_ENTRY bss_entry = bss_list->wlanBssEntries[j];
185 ap->setMac(bss_entry.dot11Bssid);
186 ap->setSignal(bss_entry.lRssi);
187 ap->setSSID(reinterpret_cast<char const*>(bss_entry.dot11Ssid.ucSSID),
188 bss_entry.dot11Ssid.uSSIDLength);
190 accessPoints.AppendObject(ap);
194 return NS_OK;