summaryrefslogtreecommitdiffstats
path: root/netwerk/wifi/win
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/wifi/win')
-rw-r--r--netwerk/wifi/win/WinWifiScanner.cpp170
-rw-r--r--netwerk/wifi/win/WinWifiScanner.h36
-rw-r--r--netwerk/wifi/win/WlanLibrary.cpp111
-rw-r--r--netwerk/wifi/win/WlanLibrary.h54
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;
+};