diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:44:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:44:51 +0000 |
commit | 9e3c08db40b8916968b9f30096c7be3f00ce9647 (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /netwerk/wifi/win | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'netwerk/wifi/win')
-rw-r--r-- | netwerk/wifi/win/WinWifiScanner.cpp | 170 | ||||
-rw-r--r-- | netwerk/wifi/win/WinWifiScanner.h | 36 | ||||
-rw-r--r-- | netwerk/wifi/win/WlanLibrary.cpp | 111 | ||||
-rw-r--r-- | netwerk/wifi/win/WlanLibrary.h | 54 |
4 files changed, 371 insertions, 0 deletions
diff --git a/netwerk/wifi/win/WinWifiScanner.cpp b/netwerk/wifi/win/WinWifiScanner.cpp new file mode 100644 index 0000000000..b24fb4a2f1 --- /dev/null +++ b/netwerk/wifi/win/WinWifiScanner.cpp @@ -0,0 +1,170 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsWifiAccessPoint.h" +#include "WinWifiScanner.h" + +#define DOT11_BSS_TYPE_UNUSED static_cast<DOT11_BSS_TYPE>(0) + +namespace mozilla { + +class InterfaceScanCallbackData { + public: + explicit InterfaceScanCallbackData(uint32_t numInterfaces) + : mCurrentlyScanningInterfaces(numInterfaces) { + mAllInterfacesDoneScanningEvent = + ::CreateEventW(nullptr, // null security + TRUE, // manual reset event + FALSE, // initially nonsignaled + nullptr); // not named + MOZ_ASSERT(NULL != mAllInterfacesDoneScanningEvent); + } + + ~InterfaceScanCallbackData() { + ::CloseHandle(mAllInterfacesDoneScanningEvent); + } + + void OnInterfaceScanComplete() { + uint32_t val = ::InterlockedDecrement(&mCurrentlyScanningInterfaces); + if (!val) { + ::SetEvent(mAllInterfacesDoneScanningEvent); + } + } + + void WaitForAllInterfacesToFinishScanning(uint32_t msToWait) { + ::WaitForSingleObject(mAllInterfacesDoneScanningEvent, msToWait); + } + + private: + volatile uint32_t mCurrentlyScanningInterfaces; + HANDLE mAllInterfacesDoneScanningEvent; +}; + +static void WINAPI OnScanComplete(PWLAN_NOTIFICATION_DATA data, PVOID context) { + if (WLAN_NOTIFICATION_SOURCE_ACM != data->NotificationSource) { + return; + } + + if (wlan_notification_acm_scan_complete != data->NotificationCode && + wlan_notification_acm_scan_fail != data->NotificationCode) { + return; + } + + InterfaceScanCallbackData* cbData = + reinterpret_cast<InterfaceScanCallbackData*>(context); + cbData->OnInterfaceScanComplete(); +} + +WifiScannerImpl::WifiScannerImpl() { + // NOTE: We assume that, if we were unable to load the WLAN library when + // we initially tried, we will not be able to load it in the future. + // Technically, on Windows XP SP2, a user could install the redistributable + // and make our assumption incorrect. We opt to avoid making a bunch of + // spurious LoadLibrary calls in the common case rather than load the + // WLAN API in the edge case. + mWlanLibrary.reset(WinWLANLibrary::Load()); + if (!mWlanLibrary) { + NS_WARNING("Could not initialize Windows Wi-Fi scanner"); + } +} + +WifiScannerImpl::~WifiScannerImpl() {} + +nsresult WifiScannerImpl::GetAccessPointsFromWLAN( + nsTArray<RefPtr<nsIWifiAccessPoint>>& accessPoints) { + accessPoints.Clear(); + + // NOTE: We do not try to load the WLAN library if we previously failed + // to load it. See the note in WifiScannerImpl constructor + if (!mWlanLibrary) { + return NS_ERROR_NOT_AVAILABLE; + } + + // Get the list of interfaces. WlanEnumInterfaces allocates interface_list. + WLAN_INTERFACE_INFO_LIST* interface_list = nullptr; + if (ERROR_SUCCESS != + (*mWlanLibrary->GetWlanEnumInterfacesPtr())(mWlanLibrary->GetWLANHandle(), + nullptr, &interface_list)) { + return NS_ERROR_FAILURE; + } + + // This ensures we call WlanFreeMemory on interface_list + ScopedWLANObject scopedInterfaceList(*mWlanLibrary, interface_list); + + if (!interface_list->dwNumberOfItems) { + return NS_OK; + } + + InterfaceScanCallbackData cbData(interface_list->dwNumberOfItems); + + DWORD wlanNotifySource; + if (ERROR_SUCCESS != (*mWlanLibrary->GetWlanRegisterNotificationPtr())( + mWlanLibrary->GetWLANHandle(), + WLAN_NOTIFICATION_SOURCE_ACM, TRUE, + (WLAN_NOTIFICATION_CALLBACK)OnScanComplete, &cbData, + NULL, &wlanNotifySource)) { + return NS_ERROR_FAILURE; + } + + // Go through the list of interfaces and call `WlanScan` on each + for (unsigned int i = 0; i < interface_list->dwNumberOfItems; ++i) { + if (ERROR_SUCCESS != (*mWlanLibrary->GetWlanScanPtr())( + mWlanLibrary->GetWLANHandle(), + &interface_list->InterfaceInfo[i].InterfaceGuid, + NULL, NULL, NULL)) { + cbData.OnInterfaceScanComplete(); + } + } + + // From the MSDN documentation: + // "Wireless network drivers that meet Windows logo requirements are + // required to complete a WlanScan function request in 4 seconds" + cbData.WaitForAllInterfacesToFinishScanning(5000); + + // Unregister for the notifications. The documentation mentions that, + // if a callback is currently running, this will wait for the callback + // to complete. + (*mWlanLibrary->GetWlanRegisterNotificationPtr())( + mWlanLibrary->GetWLANHandle(), WLAN_NOTIFICATION_SOURCE_NONE, TRUE, NULL, + NULL, NULL, &wlanNotifySource); + + // Go through the list of interfaces and get the data for each. + for (uint32_t i = 0; i < interface_list->dwNumberOfItems; ++i) { + WLAN_BSS_LIST* bss_list; + if (ERROR_SUCCESS != (*mWlanLibrary->GetWlanGetNetworkBssListPtr())( + mWlanLibrary->GetWLANHandle(), + &interface_list->InterfaceInfo[i].InterfaceGuid, + nullptr, // Use all SSIDs. + DOT11_BSS_TYPE_UNUSED, + false, // bSecurityEnabled - + // unused + nullptr, // reserved + &bss_list)) { + continue; + } + + // This ensures we call WlanFreeMemory on bss_list + ScopedWLANObject scopedBssList(*mWlanLibrary, bss_list); + + // Store each discovered access point in our outparam + for (int j = 0; j < static_cast<int>(bss_list->dwNumberOfItems); ++j) { + nsWifiAccessPoint* ap = new nsWifiAccessPoint(); + if (!ap) { + continue; + } + + const WLAN_BSS_ENTRY bss_entry = bss_list->wlanBssEntries[j]; + ap->setMac(bss_entry.dot11Bssid); + ap->setSignal(bss_entry.lRssi); + ap->setSSID(reinterpret_cast<char const*>(bss_entry.dot11Ssid.ucSSID), + bss_entry.dot11Ssid.uSSIDLength); + + accessPoints.AppendElement(ap); + } + } + + return NS_OK; +} + +} // namespace mozilla diff --git a/netwerk/wifi/win/WinWifiScanner.h b/netwerk/wifi/win/WinWifiScanner.h new file mode 100644 index 0000000000..ce36c1156d --- /dev/null +++ b/netwerk/wifi/win/WinWifiScanner.h @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +#include "mozilla/UniquePtr.h" +#include "WlanLibrary.h" +#include "WifiScanner.h" + +class nsIWifiAccessPoint; + +namespace mozilla { + +class WifiScannerImpl final : public WifiScanner { + public: + WifiScannerImpl(); + ~WifiScannerImpl(); + + /** + * GetAccessPointsFromWLAN + * + * Scans the available wireless interfaces for nearby access points and + * populates the supplied collection with them + * + * @param accessPoints The collection to populate with available APs + * @return NS_OK on success, failure codes on failure + */ + nsresult GetAccessPointsFromWLAN( + nsTArray<RefPtr<nsIWifiAccessPoint>>& accessPoints); + + private: + mozilla::UniquePtr<WinWLANLibrary> mWlanLibrary; +}; + +} // namespace mozilla diff --git a/netwerk/wifi/win/WlanLibrary.cpp b/netwerk/wifi/win/WlanLibrary.cpp new file mode 100644 index 0000000000..0fd36be660 --- /dev/null +++ b/netwerk/wifi/win/WlanLibrary.cpp @@ -0,0 +1,111 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "WlanLibrary.h" + +// Moz headers (alphabetical) + +WinWLANLibrary* WinWLANLibrary::Load() { + WinWLANLibrary* ret = new WinWLANLibrary(); + if (!ret) { + return nullptr; + } + + if (!ret->Initialize()) { + delete ret; + return nullptr; + } + + return ret; +} + +HANDLE +WinWLANLibrary::GetWLANHandle() const { return mWlanHandle; } + +decltype(::WlanEnumInterfaces)* WinWLANLibrary::GetWlanEnumInterfacesPtr() + const { + return mWlanEnumInterfacesPtr; +} + +decltype(::WlanGetNetworkBssList)* WinWLANLibrary::GetWlanGetNetworkBssListPtr() + const { + return mWlanGetNetworkBssListPtr; +} + +decltype(::WlanFreeMemory)* WinWLANLibrary::GetWlanFreeMemoryPtr() const { + return mWlanFreeMemoryPtr; +} + +decltype(::WlanCloseHandle)* WinWLANLibrary::GetWlanCloseHandlePtr() const { + return mWlanCloseHandlePtr; +} + +decltype(::WlanOpenHandle)* WinWLANLibrary::GetWlanOpenHandlePtr() const { + return mWlanOpenHandlePtr; +} + +decltype(::WlanRegisterNotification)* +WinWLANLibrary::GetWlanRegisterNotificationPtr() const { + return mWlanRegisterNotificationPtr; +} + +decltype(::WlanScan)* WinWLANLibrary::GetWlanScanPtr() const { + return mWlanScanPtr; +} + +bool WinWLANLibrary::Initialize() { + mWlanLibrary = LoadLibraryW(L"Wlanapi.dll"); + if (!mWlanLibrary) { + return false; + } + + mWlanOpenHandlePtr = (decltype(::WlanOpenHandle)*)GetProcAddress( + mWlanLibrary, "WlanOpenHandle"); + mWlanEnumInterfacesPtr = (decltype(::WlanEnumInterfaces)*)GetProcAddress( + mWlanLibrary, "WlanEnumInterfaces"); + mWlanRegisterNotificationPtr = + (decltype(::WlanRegisterNotification)*)GetProcAddress( + mWlanLibrary, "WlanRegisterNotification"); + mWlanScanPtr = + (decltype(::WlanScan)*)GetProcAddress(mWlanLibrary, "WlanScan"); + + mWlanFreeMemoryPtr = (decltype(::WlanFreeMemory)*)GetProcAddress( + mWlanLibrary, "WlanFreeMemory"); + mWlanCloseHandlePtr = (decltype(::WlanCloseHandle)*)GetProcAddress( + mWlanLibrary, "WlanCloseHandle"); + mWlanGetNetworkBssListPtr = + (decltype(::WlanGetNetworkBssList)*)GetProcAddress( + mWlanLibrary, "WlanGetNetworkBssList"); + + if (!mWlanOpenHandlePtr || !mWlanEnumInterfacesPtr || + !mWlanRegisterNotificationPtr || !mWlanGetNetworkBssListPtr || + !mWlanScanPtr || !mWlanFreeMemoryPtr || !mWlanCloseHandlePtr) { + return false; + } + + // Get the handle to the WLAN API. + DWORD negotiated_version; + // We could be executing on either Windows XP or Windows Vista, so use the + // lower version of the client WLAN API. It seems that the negotiated version + // is the Vista version irrespective of what we pass! + static const int kXpWlanClientVersion = 1; + if (ERROR_SUCCESS != (*mWlanOpenHandlePtr)(kXpWlanClientVersion, nullptr, + &negotiated_version, + &mWlanHandle)) { + return false; + } + + return true; +} + +WinWLANLibrary::~WinWLANLibrary() { + if (mWlanLibrary) { + if (mWlanHandle) { + (*mWlanCloseHandlePtr)(mWlanLibrary, mWlanHandle); + mWlanHandle = nullptr; + } + ::FreeLibrary(mWlanLibrary); + mWlanLibrary = nullptr; + } +} diff --git a/netwerk/wifi/win/WlanLibrary.h b/netwerk/wifi/win/WlanLibrary.h new file mode 100644 index 0000000000..8d996f881d --- /dev/null +++ b/netwerk/wifi/win/WlanLibrary.h @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sts=2 sw=2 et cin: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#pragma once + +// Moz headers (alphabetical) + +// System headers (alphabetical) +#include <windows.h> // HINSTANCE, HANDLE +#include <wlanapi.h> // Wlan* functions + +class WinWLANLibrary { + public: + static WinWLANLibrary* Load(); + ~WinWLANLibrary(); + + HANDLE GetWLANHandle() const; + decltype(::WlanEnumInterfaces)* GetWlanEnumInterfacesPtr() const; + decltype(::WlanGetNetworkBssList)* GetWlanGetNetworkBssListPtr() const; + decltype(::WlanFreeMemory)* GetWlanFreeMemoryPtr() const; + decltype(::WlanCloseHandle)* GetWlanCloseHandlePtr() const; + decltype(::WlanOpenHandle)* GetWlanOpenHandlePtr() const; + decltype(::WlanRegisterNotification)* GetWlanRegisterNotificationPtr() const; + decltype(::WlanScan)* GetWlanScanPtr() const; + + private: + WinWLANLibrary() = default; + bool Initialize(); + + HMODULE mWlanLibrary = nullptr; + HANDLE mWlanHandle = nullptr; + decltype(::WlanEnumInterfaces)* mWlanEnumInterfacesPtr = nullptr; + decltype(::WlanGetNetworkBssList)* mWlanGetNetworkBssListPtr = nullptr; + decltype(::WlanFreeMemory)* mWlanFreeMemoryPtr = nullptr; + decltype(::WlanCloseHandle)* mWlanCloseHandlePtr = nullptr; + decltype(::WlanOpenHandle)* mWlanOpenHandlePtr = nullptr; + decltype(::WlanRegisterNotification)* mWlanRegisterNotificationPtr = nullptr; + decltype(::WlanScan)* mWlanScanPtr = nullptr; +}; + +class ScopedWLANObject { + public: + ScopedWLANObject(const WinWLANLibrary& library, void* object) + : mLibrary(library), mObject(object) {} + + ~ScopedWLANObject() { (*(mLibrary.GetWlanFreeMemoryPtr()))(mObject); } + + private: + const WinWLANLibrary& mLibrary; + void* mObject; +}; |