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
{
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
);
32 ::SetEvent(mAllInterfacesDoneScanningEvent
);
36 void WaitForAllInterfacesToFinishScanning(uint32_t msToWait
) {
37 ::WaitForSingleObject(mAllInterfacesDoneScanningEvent
, msToWait
);
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
) {
50 if (wlan_notification_acm_scan_complete
!= data
->NotificationCode
&&
51 wlan_notification_acm_scan_fail
!= data
->NotificationCode
) {
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();
69 NS_WARNING("Could not initialize Windows Wi-Fi scanner");
73 WinWifiScanner::~WinWifiScanner() {}
75 nsresult
WinWifiScanner::GetAccessPointsFromWLAN(
76 nsCOMArray
<nsWifiAccessPoint
>& accessPoints
) {
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
82 return NS_ERROR_NOT_AVAILABLE
;
85 // Get the list of interfaces. WlanEnumInterfaces allocates interface_list.
86 WLAN_INTERFACE_INFO_LIST
* interface_list
= nullptr;
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
) {
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
,
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
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
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();
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
);