Bug 985970. On Windows, initiate a scan of nearby wireless networks before collecting AP data. r=jimm
authorTim Abraldes <tabraldes@mozilla.com>
Fri, 01 Aug 2014 12:10:48 -0700
changeset 197550 221ded3982a7b6278d850b04b13d28a81940df9d
parent 197549 ce89d709b63cbba74ff17541f1efeaa824bd70bd
child 197551 a668ab2d8dd36f35ce7b9c7f814550322ee40f0b
push id27249
push userryanvm@gmail.com
push dateMon, 04 Aug 2014 20:14:35 +0000
treeherdermozilla-central@7f81be7db528 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs985970
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 985970. On Windows, initiate a scan of nearby wireless networks before collecting AP data. r=jimm
netwerk/wifi/moz.build
netwerk/wifi/nsWifiMonitor.h
netwerk/wifi/nsWifiScannerWin.cpp
netwerk/wifi/win_wifiScanner.cpp
netwerk/wifi/win_wifiScanner.h
netwerk/wifi/win_wlanLibrary.cpp
netwerk/wifi/win_wlanLibrary.h
--- a/netwerk/wifi/moz.build
+++ b/netwerk/wifi/moz.build
@@ -37,16 +37,18 @@ if CONFIG['OS_ARCH'] == 'Darwin':
     ]
 elif CONFIG['OS_ARCH'] == 'FreeBSD':
     UNIFIED_SOURCES += [
         'nsWifiScannerFreeBSD.cpp',
     ]
 elif CONFIG['OS_ARCH'] == 'WINNT':
     UNIFIED_SOURCES += [
         'nsWifiScannerWin.cpp',
+        'win_wifiScanner.cpp',
+        'win_wlanLibrary.cpp',
     ]
 elif CONFIG['OS_ARCH'] == 'SunOS':
     CXXFLAGS += CONFIG['GLIB_CFLAGS']
     UNIFIED_SOURCES += [
         'nsWifiScannerSolaris.cpp',
     ]
 
 if CONFIG['NECKO_WIFI_DBUS']:
--- a/netwerk/wifi/nsWifiMonitor.h
+++ b/netwerk/wifi/nsWifiMonitor.h
@@ -16,16 +16,20 @@
 #include "mozilla/ReentrantMonitor.h"
 #include "prlog.h"
 #include "nsIObserver.h"
 #include "nsTArray.h"
 #include "nsITimer.h"
 #include "mozilla/Attributes.h"
 #include "nsIInterfaceRequestor.h"
 
+#ifdef XP_WIN
+class WinWifiScanner;
+#endif
+
 #if defined(PR_LOGGING)
 extern PRLogModuleInfo *gWifiMonitorLog;
 #endif
 #define LOG(args)     PR_LOG(gWifiMonitorLog, PR_LOG_DEBUG, args)
 
 class nsWifiAccessPoint;
 
 #define kDefaultWifiScanInterval 5 /* seconds */
@@ -66,16 +70,19 @@ class nsWifiMonitor MOZ_FINAL : nsIRunna
 
   bool mKeepGoing;
   nsCOMPtr<nsIThread> mThread;
 
   nsTArray<nsWifiListener> mListeners;
 
   mozilla::ReentrantMonitor mReentrantMonitor;
 
+#ifdef XP_WIN
+  nsAutoPtr<WinWifiScanner> mWinWifiScanner;
+#endif
 };
 #else
 #include "nsIWifi.h"
 class nsWifiMonitor MOZ_FINAL : nsIWifiMonitor, nsIWifiScanResultsReady, nsIObserver
 {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIWIFIMONITOR
--- a/netwerk/wifi/nsWifiScannerWin.cpp
+++ b/netwerk/wifi/nsWifiScannerWin.cpp
@@ -1,127 +1,62 @@
 /* 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 "windows.h"
-#include "wlanapi.h"
+#include "nsWifiMonitor.h"
 
-#include "stdlib.h"
-
-#include "nsWifiMonitor.h"
-#include "nsWifiAccessPoint.h"
-
-#include "nsServiceManagerUtils.h"
+// moz headers (alphabetical)
+#include "nsAutoPtr.h"
+#include "nsCOMArray.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIMutableArray.h"
-
-#define DOT11_BSS_TYPE_UNUSED static_cast<DOT11_BSS_TYPE>(0)
+#include "nsServiceManagerUtils.h"
+#include "nsWifiAccessPoint.h"
+#include "win_wifiScanner.h"
 
 using namespace mozilla;
 
+/**
+ * `nsWifiMonitor` is declared in the cross-platform nsWifiMonitor.h and
+ * is mostly defined in the cross-platform nsWifiMonitor.cpp. This function
+ * is implemented in various platform-specific files but the implementation
+ * is almost identical in each file. We relegate the Windows-specific
+ * work to the `WinWifiScanner` class and deal with non-Windows-specific
+ * issues like calling listeners here. Hopefully this file can be merged
+ * with the other implementations of `nsWifiMonitor::DoScan` since a lot
+ * of the code is identical
+ */
 nsresult
 nsWifiMonitor::DoScan()
 {
-    HINSTANCE wlan_library = LoadLibrary("Wlanapi.dll");
-    if (!wlan_library)
-      return NS_ERROR_NOT_AVAILABLE;
-
-    decltype(::WlanOpenHandle)* WlanOpenHandle = (decltype(::WlanOpenHandle)*) GetProcAddress(wlan_library, "WlanOpenHandle");
-    decltype(::WlanEnumInterfaces)* WlanEnumInterfaces = (decltype(::WlanEnumInterfaces)*) GetProcAddress(wlan_library, "WlanEnumInterfaces");
-    decltype(::WlanGetNetworkBssList)* WlanGetNetworkBssList = (decltype(::WlanGetNetworkBssList)*) GetProcAddress(wlan_library, "WlanGetNetworkBssList");
-    decltype(::WlanFreeMemory)* WlanFreeMemory = (decltype(::WlanFreeMemory)*) GetProcAddress(wlan_library, "WlanFreeMemory");
-    decltype(::WlanCloseHandle)* WlanCloseHandle = (decltype(::WlanCloseHandle)*) GetProcAddress(wlan_library, "WlanCloseHandle");
-
-    if (!WlanOpenHandle ||
-        !WlanEnumInterfaces ||
-        !WlanGetNetworkBssList ||
-        !WlanFreeMemory ||
-        !WlanCloseHandle)
-      return NS_ERROR_FAILURE;
+    if (!mWinWifiScanner) {
+      mWinWifiScanner = new WinWifiScanner();
+      if (!mWinWifiScanner) {
+        // TODO: Probably return OOM error
+        return NS_ERROR_FAILURE;
+      }
+    }
 
     // Regularly get the access point data.
 
     nsCOMArray<nsWifiAccessPoint> lastAccessPoints;
     nsCOMArray<nsWifiAccessPoint> accessPoints;
 
     do {
       accessPoints.Clear();
-
-      // Get the handle to the WLAN API.
-      DWORD negotiated_version;
-      HANDLE wlan_handle = nullptr;
-      // 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 ((*WlanOpenHandle)(kXpWlanClientVersion,
-                            nullptr,
-                            &negotiated_version,
-                            &wlan_handle) != ERROR_SUCCESS) {
-        return NS_ERROR_NOT_AVAILABLE;
-      }
-
-      // try again later.
-      if (!wlan_handle)
-        return NS_ERROR_FAILURE;
-
-      // Get the list of interfaces. WlanEnumInterfaces allocates interface_list.
-      WLAN_INTERFACE_INFO_LIST *interface_list = nullptr;
-      if ((*WlanEnumInterfaces)(wlan_handle, nullptr, &interface_list) != ERROR_SUCCESS) {
-        // try again later
-        (*WlanCloseHandle)(wlan_handle, nullptr);
-        return NS_ERROR_FAILURE;
+      nsresult rv = mWinWifiScanner->GetAccessPointsFromWLAN(accessPoints);
+      if (NS_FAILED(rv)) {
+        return rv;
       }
 
-      // Go through the list of interfaces and get the data for each.
-      for (int i = 0; i < static_cast<int>(interface_list->dwNumberOfItems); ++i) {
-
-        WLAN_BSS_LIST *bss_list;
-        HRESULT rv = (*WlanGetNetworkBssList)(wlan_handle,
-                                              &interface_list->InterfaceInfo[i].InterfaceGuid,
-                                              nullptr,  // Use all SSIDs.
-                                              DOT11_BSS_TYPE_UNUSED,
-                                              false,    // bSecurityEnabled - unused
-                                              nullptr,  // reserved
-                                              &bss_list);
-        if (rv != ERROR_SUCCESS) {
-          continue;
-        }
-
-        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((char*) bss_entry.dot11Ssid.ucSSID,
-                      bss_entry.dot11Ssid.uSSIDLength);
-
-          accessPoints.AppendObject(ap);
-        }
-        (*WlanFreeMemory)(bss_list);
-      }
-
-      // Free interface_list.
-      (*WlanFreeMemory)(interface_list);
-
-      // Close the handle.
-      (*WlanCloseHandle)(wlan_handle, nullptr);
-
-
       bool accessPointsChanged = !AccessPointsEqual(accessPoints, lastAccessPoints);
       ReplaceArray(lastAccessPoints, accessPoints);
 
-      nsresult rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
+      rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // wait for some reasonable amount of time.  pref?
       LOG(("waiting on monitor\n"));
 
       ReentrantMonitorAutoEnter mon(mReentrantMonitor);
       mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
     }
new file mode 100644
--- /dev/null
+++ b/netwerk/wifi/win_wifiScanner.cpp
@@ -0,0 +1,192 @@
+/* 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 "win_wifiScanner.h"
+
+// Moz headers (alphabetical)
+#include "win_wlanLibrary.h"
+
+#define DOT11_BSS_TYPE_UNUSED static_cast<DOT11_BSS_TYPE>(0)
+
+class InterfaceScanCallbackData {
+public:
+  InterfaceScanCallbackData(uint32_t numInterfaces)
+    : mCurrentlyScanningInterfaces(numInterfaces)
+  {
+    mAllInterfacesDoneScanningEvent =
+      ::CreateEvent(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
+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();
+}
+
+WinWifiScanner::WinWifiScanner()
+{
+  // 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 = WinWLANLibrary::Load();
+  MOZ_ASSERT(mWlanLibrary);
+}
+
+WinWifiScanner::~WinWifiScanner()
+{
+}
+
+nsresult
+WinWifiScanner::GetAccessPointsFromWLAN(nsCOMArray<nsWifiAccessPoint> &accessPoints)
+{
+  accessPoints.Clear();
+
+  // NOTE: We do not try to load the WLAN library if we previously failed
+  // to load it. See the note in WinWifiScanner 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.AppendObject(ap);
+    }
+  }
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/netwerk/wifi/win_wifiScanner.h
@@ -0,0 +1,32 @@
+/* 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)
+#include "nsAutoPtr.h"
+#include "nsCOMArray.h"
+
+class nsWifiAccessPoint;
+class WinWLANLibrary;
+
+class WinWifiScanner {
+ public:
+  WinWifiScanner();
+  ~WinWifiScanner();
+
+  /**
+   * 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(nsCOMArray<nsWifiAccessPoint> &accessPoints);
+
+ private:
+  nsAutoPtr<WinWLANLibrary> mWlanLibrary;
+};
new file mode 100644
--- /dev/null
+++ b/netwerk/wifi/win_wlanLibrary.cpp
@@ -0,0 +1,155 @@
+/* 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 "win_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;
+}
+
+WinWLANLibrary::WinWLANLibrary()
+  : mWlanLibrary(nullptr),
+    mWlanHandle(nullptr),
+    mWlanEnumInterfacesPtr(nullptr),
+    mWlanGetNetworkBssListPtr(nullptr),
+    mWlanFreeMemoryPtr(nullptr),
+    mWlanCloseHandlePtr(nullptr),
+    mWlanOpenHandlePtr(nullptr),
+    mWlanRegisterNotificationPtr(nullptr),
+    mWlanScanPtr(nullptr)
+{
+}
+
+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 = LoadLibrary("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;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/netwerk/wifi/win_wlanLibrary.h
@@ -0,0 +1,59 @@
+/* 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();
+  bool Initialize();
+
+  HMODULE mWlanLibrary;
+  HANDLE mWlanHandle;
+  decltype(::WlanEnumInterfaces)* mWlanEnumInterfacesPtr;
+  decltype(::WlanGetNetworkBssList)* mWlanGetNetworkBssListPtr;
+  decltype(::WlanFreeMemory)* mWlanFreeMemoryPtr;
+  decltype(::WlanCloseHandle)* mWlanCloseHandlePtr;
+  decltype(::WlanOpenHandle)* mWlanOpenHandlePtr;
+  decltype(::WlanRegisterNotification)* mWlanRegisterNotificationPtr;
+  decltype(::WlanScan)* mWlanScanPtr;
+};
+
+class ScopedWLANObject {
+public:
+ ScopedWLANObject(WinWLANLibrary* library, void* object)
+   : mObject(object),
+    mLibrary(library)
+  {
+  }
+
+  ~ScopedWLANObject()
+  {
+    (*(mLibrary->GetWlanFreeMemoryPtr()))(mObject);
+  }
+
+ private:
+  WinWLANLibrary *mLibrary;
+  void *mObject;
+};