Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / netwerk / wifi / win_wifiScanner.cpp
blob4f405e0e106c1480cf95cbc276bc743334171482
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 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 MOZ_ASSERT(mWlanLibrary);
81 WinWifiScanner::~WinWifiScanner()
85 nsresult
86 WinWifiScanner::GetAccessPointsFromWLAN(nsCOMArray<nsWifiAccessPoint> &accessPoints)
88 accessPoints.Clear();
90 // NOTE: We do not try to load the WLAN library if we previously failed
91 // to load it. See the note in WinWifiScanner constructor
92 if (!mWlanLibrary) {
93 return NS_ERROR_NOT_AVAILABLE;
96 // Get the list of interfaces. WlanEnumInterfaces allocates interface_list.
97 WLAN_INTERFACE_INFO_LIST *interface_list = nullptr;
98 if (ERROR_SUCCESS !=
99 (*mWlanLibrary->GetWlanEnumInterfacesPtr())(mWlanLibrary->GetWLANHandle(),
100 nullptr,
101 &interface_list)) {
102 return NS_ERROR_FAILURE;
105 // This ensures we call WlanFreeMemory on interface_list
106 ScopedWLANObject scopedInterfaceList(mWlanLibrary, interface_list);
108 if (!interface_list->dwNumberOfItems) {
109 return NS_OK;
112 InterfaceScanCallbackData cbData(interface_list->dwNumberOfItems);
114 DWORD wlanNotifySource;
115 if (ERROR_SUCCESS !=
116 (*mWlanLibrary->GetWlanRegisterNotificationPtr())(
117 mWlanLibrary->GetWLANHandle(),
118 WLAN_NOTIFICATION_SOURCE_ACM,
119 TRUE,
120 (WLAN_NOTIFICATION_CALLBACK)OnScanComplete,
121 &cbData,
122 NULL,
123 &wlanNotifySource)) {
124 return NS_ERROR_FAILURE;
127 // Go through the list of interfaces and call `WlanScan` on each
128 for (unsigned int i = 0; i < interface_list->dwNumberOfItems; ++i) {
129 if (ERROR_SUCCESS !=
130 (*mWlanLibrary->GetWlanScanPtr())(
131 mWlanLibrary->GetWLANHandle(),
132 &interface_list->InterfaceInfo[i].InterfaceGuid,
133 NULL,
134 NULL,
135 NULL)) {
136 cbData.OnInterfaceScanComplete();
140 // From the MSDN documentation:
141 // "Wireless network drivers that meet Windows logo requirements are
142 // required to complete a WlanScan function request in 4 seconds"
143 cbData.WaitForAllInterfacesToFinishScanning(5000);
145 // Unregister for the notifications. The documentation mentions that,
146 // if a callback is currently running, this will wait for the callback
147 // to complete.
148 (*mWlanLibrary->GetWlanRegisterNotificationPtr())(
149 mWlanLibrary->GetWLANHandle(),
150 WLAN_NOTIFICATION_SOURCE_NONE,
151 TRUE,
152 NULL,
153 NULL,
154 NULL,
155 &wlanNotifySource);
157 // Go through the list of interfaces and get the data for each.
158 for (uint32_t i = 0; i < interface_list->dwNumberOfItems; ++i) {
159 WLAN_BSS_LIST *bss_list;
160 if (ERROR_SUCCESS !=
161 (*mWlanLibrary->GetWlanGetNetworkBssListPtr())(
162 mWlanLibrary->GetWLANHandle(),
163 &interface_list->InterfaceInfo[i].InterfaceGuid,
164 nullptr, // Use all SSIDs.
165 DOT11_BSS_TYPE_UNUSED,
166 false, // bSecurityEnabled - unused
167 nullptr, // reserved
168 &bss_list)) {
169 continue;
172 // This ensures we call WlanFreeMemory on bss_list
173 ScopedWLANObject scopedBssList(mWlanLibrary, bss_list);
175 // Store each discovered access point in our outparam
176 for (int j = 0; j < static_cast<int>(bss_list->dwNumberOfItems); ++j) {
177 nsWifiAccessPoint* ap = new nsWifiAccessPoint();
178 if (!ap) {
179 continue;
182 const WLAN_BSS_ENTRY bss_entry = bss_list->wlanBssEntries[j];
183 ap->setMac(bss_entry.dot11Bssid);
184 ap->setSignal(bss_entry.lRssi);
185 ap->setSSID(reinterpret_cast<char const*>(bss_entry.dot11Ssid.ucSSID),
186 bss_entry.dot11Ssid.uSSIDLength);
188 accessPoints.AppendObject(ap);
192 return NS_OK;