summaryrefslogtreecommitdiffstats
path: root/netwerk/wifi
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /netwerk/wifi
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'netwerk/wifi')
-rw-r--r--netwerk/wifi/moz.build65
-rw-r--r--netwerk/wifi/nsIWifiAccessPoint.idl41
-rw-r--r--netwerk/wifi/nsIWifiListener.idl29
-rw-r--r--netwerk/wifi/nsIWifiMonitor.idl24
-rw-r--r--netwerk/wifi/nsWifiAccessPoint.cpp95
-rw-r--r--netwerk/wifi/nsWifiAccessPoint.h86
-rw-r--r--netwerk/wifi/nsWifiMonitor.cpp265
-rw-r--r--netwerk/wifi/nsWifiMonitor.h110
-rw-r--r--netwerk/wifi/nsWifiMonitorGonk.cpp181
-rw-r--r--netwerk/wifi/nsWifiScannerDBus.cpp337
-rw-r--r--netwerk/wifi/nsWifiScannerDBus.h45
-rw-r--r--netwerk/wifi/nsWifiScannerFreeBSD.cpp171
-rw-r--r--netwerk/wifi/nsWifiScannerMac.cpp55
-rw-r--r--netwerk/wifi/nsWifiScannerSolaris.cpp149
-rw-r--r--netwerk/wifi/nsWifiScannerWin.cpp77
-rw-r--r--netwerk/wifi/osx_corewlan.mm108
-rw-r--r--netwerk/wifi/osx_wifi.h120
-rw-r--r--netwerk/wifi/tests/wifi_access_point_test.html60
-rw-r--r--netwerk/wifi/win_wifiScanner.cpp195
-rw-r--r--netwerk/wifi/win_wifiScanner.h41
-rw-r--r--netwerk/wifi/win_wlanLibrary.cpp155
-rw-r--r--netwerk/wifi/win_wlanLibrary.h61
-rw-r--r--netwerk/wifi/win_xp_wifiScanner.cpp399
-rw-r--r--netwerk/wifi/win_xp_wifiScanner.h25
24 files changed, 2894 insertions, 0 deletions
diff --git a/netwerk/wifi/moz.build b/netwerk/wifi/moz.build
new file mode 100644
index 000000000..b6ddd2139
--- /dev/null
+++ b/netwerk/wifi/moz.build
@@ -0,0 +1,65 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+XPIDL_SOURCES += [
+ 'nsIWifiAccessPoint.idl',
+ 'nsIWifiListener.idl',
+ 'nsIWifiMonitor.idl',
+]
+
+XPIDL_MODULE = 'necko_wifi'
+
+UNIFIED_SOURCES += [
+ 'nsWifiAccessPoint.cpp',
+]
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
+ UNIFIED_SOURCES += [
+ 'nsWifiMonitorGonk.cpp',
+ ]
+else:
+ UNIFIED_SOURCES += [
+ 'nsWifiMonitor.cpp',
+ ]
+
+if CONFIG['OS_ARCH'] == 'Darwin':
+ UNIFIED_SOURCES += [
+ 'nsWifiScannerMac.cpp',
+ ]
+ SOURCES += [
+ 'osx_corewlan.mm',
+ ]
+ # osx_corewlan.mm has warnings about scanForNetworksWithParameters,
+ # bssidData and rssi. These are APIs that were removed in 10.7, so we need
+ # to accept the warnings when targeting the newer SDKs.
+ SOURCES['osx_corewlan.mm'].flags += ['-Wno-error=objc-method-access']
+elif CONFIG['OS_ARCH'] in ('DragonFly', 'FreeBSD'):
+ UNIFIED_SOURCES += [
+ 'nsWifiScannerFreeBSD.cpp',
+ ]
+elif CONFIG['OS_ARCH'] == 'WINNT':
+ UNIFIED_SOURCES += [
+ 'nsWifiScannerWin.cpp',
+ 'win_wifiScanner.cpp',
+ 'win_wlanLibrary.cpp',
+ 'win_xp_wifiScanner.cpp'
+ ]
+elif CONFIG['OS_ARCH'] == 'SunOS':
+ CXXFLAGS += CONFIG['GLIB_CFLAGS']
+ UNIFIED_SOURCES += [
+ 'nsWifiScannerSolaris.cpp',
+ ]
+
+if CONFIG['NECKO_WIFI_DBUS']:
+ UNIFIED_SOURCES += [
+ 'nsWifiScannerDBus.cpp',
+ ]
+ CXXFLAGS += ['-Wno-error=shadow']
+
+if CONFIG['NECKO_WIFI_DBUS']:
+ CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
+
+FINAL_LIBRARY = 'xul'
diff --git a/netwerk/wifi/nsIWifiAccessPoint.idl b/netwerk/wifi/nsIWifiAccessPoint.idl
new file mode 100644
index 000000000..c98b42edc
--- /dev/null
+++ b/netwerk/wifi/nsIWifiAccessPoint.idl
@@ -0,0 +1,41 @@
+/* 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 "nsISupports.idl"
+
+[scriptable, uuid(E28E614F-8F86-44FF-BCF5-5F18225834A0)]
+interface nsIWifiAccessPoint : nsISupports
+{
+
+ /*
+ * The mac address of the WiFi node. The format of this string is:
+ * XX-XX-XX-XX-XX-XX
+ */
+
+ readonly attribute ACString mac;
+
+ /*
+ * Public name of a wireless network. The charset of this string is ASCII.
+ * This string will be null if not available.
+ *
+ * Note that this is a conversion of the SSID which makes it "displayable".
+ * for any comparisons, you want to use the Raw SSID.
+ */
+
+ readonly attribute AString ssid;
+
+ /*
+ * Public name of a wireless network. These are the bytes that are read off
+ * of the network, may contain nulls, and generally shouldn't be displayed to
+ * the user.
+ *
+ */
+
+ readonly attribute ACString rawSSID;
+
+ /*
+ * Current signal strength measured in dBm.
+ */
+ readonly attribute long signal;
+};
diff --git a/netwerk/wifi/nsIWifiListener.idl b/netwerk/wifi/nsIWifiListener.idl
new file mode 100644
index 000000000..ffac02654
--- /dev/null
+++ b/netwerk/wifi/nsIWifiListener.idl
@@ -0,0 +1,29 @@
+/* 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 "nsISupports.idl"
+
+interface nsIWifiAccessPoint;
+
+[scriptable, uuid(BCD4BEDE-F4A5-4A62-9071-D7A60174E376)]
+interface nsIWifiListener : nsISupports
+{
+ /*
+ * Called when the list of access points changes.
+ *
+ * @param accessPoints An array of nsIWifiAccessPoint representing all
+ * access points in view.
+ */
+
+ void onChange([array, size_is(aLen)] in nsIWifiAccessPoint accessPoints, in unsigned long aLen);
+
+ /*
+ * Called when there is a problem with listening to wifi
+ *
+ * @param error the error which caused this event. The
+ * error values will be nsresult codes.
+ */
+
+ void onError(in nsresult error);
+};
diff --git a/netwerk/wifi/nsIWifiMonitor.idl b/netwerk/wifi/nsIWifiMonitor.idl
new file mode 100644
index 000000000..aaa318d25
--- /dev/null
+++ b/netwerk/wifi/nsIWifiMonitor.idl
@@ -0,0 +1,24 @@
+/* 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 "nsISupports.idl"
+
+interface nsIWifiListener;
+
+[scriptable, uuid(F289701E-D9AF-4685-BC2F-E4226FF7C018)]
+interface nsIWifiMonitor : nsISupports
+{
+
+ /*
+ * startWatching
+ * aListener will be called once, then each time the list of wifi access points change.
+ */
+ void startWatching(in nsIWifiListener aListener);
+
+ /*
+ * stopWatching
+ * cancels all notifications to the |aListener|.
+ */
+ void stopWatching(in nsIWifiListener aListener);
+};
diff --git a/netwerk/wifi/nsWifiAccessPoint.cpp b/netwerk/wifi/nsWifiAccessPoint.cpp
new file mode 100644
index 000000000..995afaba5
--- /dev/null
+++ b/netwerk/wifi/nsWifiAccessPoint.cpp
@@ -0,0 +1,95 @@
+/* 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 "nsString.h"
+#include "nsMemory.h"
+#include "mozilla/Logging.h"
+
+extern mozilla::LazyLogModule gWifiMonitorLog;
+#define LOG(args) MOZ_LOG(gWifiMonitorLog, mozilla::LogLevel::Debug, args)
+
+NS_IMPL_ISUPPORTS(nsWifiAccessPoint, nsIWifiAccessPoint)
+
+nsWifiAccessPoint::nsWifiAccessPoint()
+{
+ // make sure these are null terminated (because we are paranoid)
+ mMac[0] = '\0';
+ mSsid[0] = '\0';
+ mSsidLen = 0;
+ mSignal = -1000;
+}
+
+nsWifiAccessPoint::~nsWifiAccessPoint()
+{
+}
+
+NS_IMETHODIMP nsWifiAccessPoint::GetMac(nsACString& aMac)
+{
+ aMac.Assign(mMac);
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsWifiAccessPoint::GetSsid(nsAString& aSsid)
+{
+ // just assign and embedded nulls will truncate resulting
+ // in a displayable string.
+ CopyASCIItoUTF16(mSsid, aSsid);
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsWifiAccessPoint::GetRawSSID(nsACString& aRawSsid)
+{
+ aRawSsid.Assign(mSsid, mSsidLen); // SSIDs are 32 chars long
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsWifiAccessPoint::GetSignal(int32_t *aSignal)
+{
+ NS_ENSURE_ARG(aSignal);
+ *aSignal = mSignal;
+ return NS_OK;
+}
+
+// Helper functions:
+
+bool AccessPointsEqual(nsCOMArray<nsWifiAccessPoint>& a, nsCOMArray<nsWifiAccessPoint>& b)
+{
+ if (a.Count() != b.Count()) {
+ LOG(("AccessPoint lists have different lengths\n"));
+ return false;
+ }
+
+ for (int32_t i = 0; i < a.Count(); i++) {
+ LOG(("++ Looking for %s\n", a[i]->mSsid));
+ bool found = false;
+ for (int32_t j = 0; j < b.Count(); j++) {
+ LOG((" %s->%s | %s->%s\n", a[i]->mSsid, b[j]->mSsid, a[i]->mMac, b[j]->mMac));
+ if (!strcmp(a[i]->mSsid, b[j]->mSsid) &&
+ !strcmp(a[i]->mMac, b[j]->mMac) &&
+ a[i]->mSignal == b[j]->mSignal) {
+ found = true;
+ }
+ }
+ if (!found)
+ return false;
+ }
+ LOG((" match!\n"));
+ return true;
+}
+
+void ReplaceArray(nsCOMArray<nsWifiAccessPoint>& a, nsCOMArray<nsWifiAccessPoint>& b)
+{
+ a.Clear();
+
+ // better way to copy?
+ for (int32_t i = 0; i < b.Count(); i++) {
+ a.AppendObject(b[i]);
+ }
+
+ b.Clear();
+}
+
+
diff --git a/netwerk/wifi/nsWifiAccessPoint.h b/netwerk/wifi/nsWifiAccessPoint.h
new file mode 100644
index 000000000..4bfb7c175
--- /dev/null
+++ b/netwerk/wifi/nsWifiAccessPoint.h
@@ -0,0 +1,86 @@
+/* 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/. */
+
+#ifndef __nsWifiAccessPoint__
+#define __nsWifiAccessPoint__
+
+#include <algorithm>
+#include "nsWifiMonitor.h"
+#include "nsIWifiAccessPoint.h"
+
+#include "nsString.h"
+#include "nsCOMArray.h"
+#include "mozilla/ArrayUtils.h" // ArrayLength
+#include "mozilla/Attributes.h"
+#include "mozilla/Sprintf.h"
+
+class nsWifiAccessPoint final : public nsIWifiAccessPoint
+{
+ ~nsWifiAccessPoint();
+
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIWIFIACCESSPOINT
+
+ nsWifiAccessPoint();
+
+ char mMac[18];
+ int mSignal;
+ char mSsid[33];
+ int mSsidLen;
+
+ void setSignal(int signal)
+ {
+ mSignal = signal;
+ }
+
+ void setMacRaw(const char* aString)
+ {
+ memcpy(mMac, aString, mozilla::ArrayLength(mMac));
+ }
+
+ void setMac(const unsigned char mac_as_int[6])
+ {
+ // mac_as_int is big-endian. Write in byte chunks.
+ // Format is XX-XX-XX-XX-XX-XX.
+
+ const unsigned char holder[6] = {0};
+ if (!mac_as_int) {
+ mac_as_int = holder;
+ }
+
+ static const char *kMacFormatString = ("%02x-%02x-%02x-%02x-%02x-%02x");
+
+ SprintfLiteral(mMac, kMacFormatString,
+ mac_as_int[0], mac_as_int[1], mac_as_int[2],
+ mac_as_int[3], mac_as_int[4], mac_as_int[5]);
+
+ mMac[17] = 0;
+ }
+
+ void setSSIDRaw(const char* aSSID, size_t len) {
+ mSsidLen = std::min(len, mozilla::ArrayLength(mSsid));
+ memcpy(mSsid, aSSID, mSsidLen);
+ }
+
+ void setSSID(const char* aSSID, unsigned long len) {
+ if (aSSID && (len < sizeof(mSsid))) {
+ strncpy(mSsid, aSSID, len);
+ mSsid[len] = 0;
+ mSsidLen = len;
+ }
+ else
+ {
+ mSsid[0] = 0;
+ mSsidLen = 0;
+ }
+ }
+};
+
+// Helper functions
+
+bool AccessPointsEqual(nsCOMArray<nsWifiAccessPoint>& a, nsCOMArray<nsWifiAccessPoint>& b);
+void ReplaceArray(nsCOMArray<nsWifiAccessPoint>& a, nsCOMArray<nsWifiAccessPoint>& b);
+
+#endif
diff --git a/netwerk/wifi/nsWifiMonitor.cpp b/netwerk/wifi/nsWifiMonitor.cpp
new file mode 100644
index 000000000..4613a107d
--- /dev/null
+++ b/netwerk/wifi/nsWifiMonitor.cpp
@@ -0,0 +1,265 @@
+/* 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 "nsCOMPtr.h"
+#include "nsProxyRelease.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
+#include "nsXPCOM.h"
+#include "nsXPCOMCID.h"
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+#include "nsWifiMonitor.h"
+#include "nsWifiAccessPoint.h"
+
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "mozilla/Services.h"
+
+using namespace mozilla;
+
+LazyLogModule gWifiMonitorLog("WifiMonitor");
+
+NS_IMPL_ISUPPORTS(nsWifiMonitor,
+ nsIRunnable,
+ nsIObserver,
+ nsIWifiMonitor)
+
+nsWifiMonitor::nsWifiMonitor()
+: mKeepGoing(true)
+, mThreadComplete(false)
+, mReentrantMonitor("nsWifiMonitor.mReentrantMonitor")
+{
+ nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
+ if (obsSvc)
+ obsSvc->AddObserver(this, "xpcom-shutdown", false);
+
+ LOG(("@@@@@ wifimonitor created\n"));
+}
+
+nsWifiMonitor::~nsWifiMonitor()
+{
+}
+
+NS_IMETHODIMP
+nsWifiMonitor::Observe(nsISupports *subject, const char *topic,
+ const char16_t *data)
+{
+ if (!strcmp(topic, "xpcom-shutdown")) {
+ LOG(("Shutting down\n"));
+
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+ mKeepGoing = false;
+ mon.Notify();
+ mThread = nullptr;
+ }
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsWifiMonitor::StartWatching(nsIWifiListener *aListener)
+{
+ LOG(("nsWifiMonitor::StartWatching %p thread %p listener %p\n",
+ this, mThread.get(), aListener));
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!aListener)
+ return NS_ERROR_NULL_POINTER;
+ if (!mKeepGoing) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsresult rv = NS_OK;
+
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+ if (mThreadComplete) {
+ // generally there is just one thread for the lifetime of the service,
+ // but if DoScan returns with an error before shutdown (i.e. !mKeepGoing)
+ // then we will respawn the thread.
+ LOG(("nsWifiMonitor::StartWatching %p restarting thread\n", this));
+ mThreadComplete = false;
+ mThread = nullptr;
+ }
+
+ if (!mThread) {
+ rv = NS_NewThread(getter_AddRefs(mThread), this);
+ if (NS_FAILED(rv))
+ return rv;
+ }
+
+
+ mListeners.AppendElement(nsWifiListener(new nsMainThreadPtrHolder<nsIWifiListener>(aListener)));
+
+ // tell ourselves that we have a new watcher.
+ mon.Notify();
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsWifiMonitor::StopWatching(nsIWifiListener *aListener)
+{
+ LOG(("nsWifiMonitor::StopWatching %p thread %p listener %p\n",
+ this, mThread.get(), aListener));
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!aListener)
+ return NS_ERROR_NULL_POINTER;
+
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+
+ for (uint32_t i = 0; i < mListeners.Length(); i++) {
+
+ if (mListeners[i].mListener == aListener) {
+ mListeners.RemoveElementAt(i);
+ break;
+ }
+ }
+
+ return NS_OK;
+}
+
+typedef nsTArray<nsMainThreadPtrHandle<nsIWifiListener> > WifiListenerArray;
+
+class nsPassErrorToWifiListeners final : public nsIRunnable
+{
+ public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIRUNNABLE
+
+ nsPassErrorToWifiListeners(nsAutoPtr<WifiListenerArray> aListeners,
+ nsresult aResult)
+ : mListeners(aListeners),
+ mResult(aResult)
+ {}
+
+ private:
+ ~nsPassErrorToWifiListeners() {}
+ nsAutoPtr<WifiListenerArray> mListeners;
+ nsresult mResult;
+};
+
+NS_IMPL_ISUPPORTS(nsPassErrorToWifiListeners,
+ nsIRunnable)
+
+NS_IMETHODIMP nsPassErrorToWifiListeners::Run()
+{
+ LOG(("About to send error to the wifi listeners\n"));
+ for (size_t i = 0; i < mListeners->Length(); i++) {
+ (*mListeners)[i]->OnError(mResult);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsWifiMonitor::Run()
+{
+ LOG(("@@@@@ wifi monitor run called\n"));
+
+ PR_SetCurrentThreadName("Wifi Monitor");
+
+ nsresult rv = DoScan();
+ LOG(("@@@@@ wifi monitor run::doscan complete %x\n", rv));
+
+ nsAutoPtr<WifiListenerArray> currentListeners;
+ bool doError = false;
+
+ {
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+ if (mKeepGoing && NS_FAILED(rv)) {
+ doError = true;
+ currentListeners = new WifiListenerArray(mListeners.Length());
+ for (uint32_t i = 0; i < mListeners.Length(); i++)
+ currentListeners->AppendElement(mListeners[i].mListener);
+ }
+ mThreadComplete = true;
+ }
+
+ if (doError) {
+ nsCOMPtr<nsIThread> thread = do_GetMainThread();
+ if (!thread)
+ return NS_ERROR_UNEXPECTED;
+
+ nsCOMPtr<nsIRunnable> runnable(new nsPassErrorToWifiListeners(currentListeners, rv));
+ if (!runnable)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ thread->Dispatch(runnable, NS_DISPATCH_SYNC);
+ }
+
+ LOG(("@@@@@ wifi monitor run complete\n"));
+ return NS_OK;
+}
+
+class nsCallWifiListeners final : public nsIRunnable
+{
+ public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIRUNNABLE
+
+ nsCallWifiListeners(nsAutoPtr<WifiListenerArray> aListeners,
+ nsAutoPtr<nsTArray<nsIWifiAccessPoint*> > aAccessPoints)
+ : mListeners(aListeners),
+ mAccessPoints(aAccessPoints)
+ {}
+
+ private:
+ ~nsCallWifiListeners() {}
+ nsAutoPtr<WifiListenerArray> mListeners;
+ nsAutoPtr<nsTArray<nsIWifiAccessPoint*> > mAccessPoints;
+};
+
+NS_IMPL_ISUPPORTS(nsCallWifiListeners,
+ nsIRunnable)
+
+NS_IMETHODIMP nsCallWifiListeners::Run()
+{
+ LOG(("About to send data to the wifi listeners\n"));
+ for (size_t i = 0; i < mListeners->Length(); i++) {
+ (*mListeners)[i]->OnChange(mAccessPoints->Elements(), mAccessPoints->Length());
+ }
+ return NS_OK;
+}
+
+nsresult
+nsWifiMonitor::CallWifiListeners(const nsCOMArray<nsWifiAccessPoint> &aAccessPoints,
+ bool aAccessPointsChanged)
+{
+ nsAutoPtr<WifiListenerArray> currentListeners;
+ {
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+
+ currentListeners = new WifiListenerArray(mListeners.Length());
+
+ for (uint32_t i = 0; i < mListeners.Length(); i++) {
+ if (!mListeners[i].mHasSentData || aAccessPointsChanged) {
+ mListeners[i].mHasSentData = true;
+ currentListeners->AppendElement(mListeners[i].mListener);
+ }
+ }
+ }
+
+ if (currentListeners->Length() > 0)
+ {
+ uint32_t resultCount = aAccessPoints.Count();
+ nsAutoPtr<nsTArray<nsIWifiAccessPoint*> > accessPoints(
+ new nsTArray<nsIWifiAccessPoint *>(resultCount));
+ if (!accessPoints)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ for (uint32_t i = 0; i < resultCount; i++)
+ accessPoints->AppendElement(aAccessPoints[i]);
+
+ nsCOMPtr<nsIThread> thread = do_GetMainThread();
+ if (!thread)
+ return NS_ERROR_UNEXPECTED;
+
+ nsCOMPtr<nsIRunnable> runnable(
+ new nsCallWifiListeners(currentListeners, accessPoints));
+ if (!runnable)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ thread->Dispatch(runnable, NS_DISPATCH_SYNC);
+ }
+
+ return NS_OK;
+}
diff --git a/netwerk/wifi/nsWifiMonitor.h b/netwerk/wifi/nsWifiMonitor.h
new file mode 100644
index 000000000..3783d38bd
--- /dev/null
+++ b/netwerk/wifi/nsWifiMonitor.h
@@ -0,0 +1,110 @@
+/* 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/. */
+
+#ifndef __nsWifiMonitor__
+#define __nsWifiMonitor__
+
+#include "nsIWifiMonitor.h"
+#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
+#include "nsProxyRelease.h"
+#include "nsIThread.h"
+#include "nsIRunnable.h"
+#include "nsCOMArray.h"
+#include "nsIWifiListener.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/ReentrantMonitor.h"
+#include "mozilla/Logging.h"
+#include "nsIObserver.h"
+#include "nsTArray.h"
+#include "nsITimer.h"
+#include "mozilla/Attributes.h"
+#include "nsIInterfaceRequestor.h"
+
+#ifdef XP_WIN
+#include "win_wifiScanner.h"
+#endif
+
+extern mozilla::LazyLogModule gWifiMonitorLog;
+#define LOG(args) MOZ_LOG(gWifiMonitorLog, mozilla::LogLevel::Debug, args)
+
+class nsWifiAccessPoint;
+
+#define kDefaultWifiScanInterval 5 /* seconds */
+
+class nsWifiListener
+{
+ public:
+
+ explicit nsWifiListener(nsMainThreadPtrHolder<nsIWifiListener>* aListener)
+ {
+ mListener = aListener;
+ mHasSentData = false;
+ }
+ ~nsWifiListener() {}
+
+ nsMainThreadPtrHandle<nsIWifiListener> mListener;
+ bool mHasSentData;
+};
+
+#ifndef MOZ_WIDGET_GONK
+class nsWifiMonitor final : nsIRunnable, nsIWifiMonitor, nsIObserver
+{
+ public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIWIFIMONITOR
+ NS_DECL_NSIRUNNABLE
+ NS_DECL_NSIOBSERVER
+
+ nsWifiMonitor();
+
+ private:
+ ~nsWifiMonitor();
+
+ nsresult DoScan();
+
+ nsresult CallWifiListeners(const nsCOMArray<nsWifiAccessPoint> &aAccessPoints,
+ bool aAccessPointsChanged);
+
+ mozilla::Atomic<bool> mKeepGoing;
+ mozilla::Atomic<bool> mThreadComplete;
+ nsCOMPtr<nsIThread> mThread;
+
+ nsTArray<nsWifiListener> mListeners;
+
+ mozilla::ReentrantMonitor mReentrantMonitor;
+
+#ifdef XP_WIN
+ nsAutoPtr<WindowsWifiScannerInterface> mWinWifiScanner;
+#endif
+};
+#else
+#include "nsIWifi.h"
+class nsWifiMonitor final : nsIWifiMonitor, nsIWifiScanResultsReady, nsIObserver
+{
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIWIFIMONITOR
+ NS_DECL_NSIOBSERVER
+ NS_DECL_NSIWIFISCANRESULTSREADY
+
+ nsWifiMonitor();
+
+ private:
+ ~nsWifiMonitor();
+
+ void ClearTimer() {
+ if (mTimer) {
+ mTimer->Cancel();
+ mTimer = nullptr;
+ }
+ }
+ void StartScan();
+ nsCOMArray<nsWifiAccessPoint> mLastAccessPoints;
+ nsTArray<nsWifiListener> mListeners;
+ nsCOMPtr<nsITimer> mTimer;
+};
+#endif
+
+#endif
diff --git a/netwerk/wifi/nsWifiMonitorGonk.cpp b/netwerk/wifi/nsWifiMonitorGonk.cpp
new file mode 100644
index 000000000..017750549
--- /dev/null
+++ b/netwerk/wifi/nsWifiMonitorGonk.cpp
@@ -0,0 +1,181 @@
+/* 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 "nsCOMPtr.h"
+#include "nsComponentManagerUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
+#include "nsXPCOM.h"
+#include "nsXPCOMCID.h"
+#include "nsIObserver.h"
+#include "nsIObserverService.h"
+#include "nsWifiMonitor.h"
+#include "nsWifiAccessPoint.h"
+
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "mozilla/Services.h"
+
+#include "nsIInterfaceRequestor.h"
+#include "nsIInterfaceRequestorUtils.h"
+
+using namespace mozilla;
+
+LazyLogModule gWifiMonitorLog("WifiMonitor");
+
+NS_IMPL_ISUPPORTS(nsWifiMonitor,
+ nsIWifiMonitor,
+ nsIObserver,
+ nsIWifiScanResultsReady)
+
+nsWifiMonitor::nsWifiMonitor()
+{
+ nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
+ if (obsSvc) {
+ obsSvc->AddObserver(this, "xpcom-shutdown", false);
+ }
+ LOG(("@@@@@ wifimonitor created\n"));
+}
+
+nsWifiMonitor::~nsWifiMonitor()
+{
+}
+
+NS_IMETHODIMP
+nsWifiMonitor::StartWatching(nsIWifiListener *aListener)
+{
+ LOG(("@@@@@ nsWifiMonitor::StartWatching\n"));
+ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+ if (!aListener) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ mListeners.AppendElement(nsWifiListener(new nsMainThreadPtrHolder<nsIWifiListener>(aListener)));
+
+ if (!mTimer) {
+ mTimer = do_CreateInstance("@mozilla.org/timer;1");
+ mTimer->Init(this, 5000, nsITimer::TYPE_REPEATING_SLACK);
+ }
+ StartScan();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWifiMonitor::StopWatching(nsIWifiListener *aListener)
+{
+ LOG(("@@@@@ nsWifiMonitor::StopWatching\n"));
+ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+ if (!aListener) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ for (uint32_t i = 0; i < mListeners.Length(); i++) {
+ if (mListeners[i].mListener == aListener) {
+ mListeners.RemoveElementAt(i);
+ break;
+ }
+ }
+
+ if (mListeners.Length() == 0) {
+ ClearTimer();
+ }
+ return NS_OK;
+}
+
+void
+nsWifiMonitor::StartScan()
+{
+ nsCOMPtr<nsIInterfaceRequestor> ir = do_GetService("@mozilla.org/telephony/system-worker-manager;1");
+ nsCOMPtr<nsIWifi> wifi = do_GetInterface(ir);
+ if (!wifi) {
+ return;
+ }
+ wifi->GetWifiScanResults(this);
+}
+
+NS_IMETHODIMP
+nsWifiMonitor::Observe(nsISupports *subject, const char *topic,
+ const char16_t *data)
+{
+ if (!strcmp(topic, "timer-callback")) {
+ LOG(("timer callback\n"));
+ StartScan();
+ return NS_OK;
+ }
+
+ if (!strcmp(topic, "xpcom-shutdown")) {
+ LOG(("Shutting down\n"));
+ ClearTimer();
+ return NS_OK;
+ }
+
+ return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+nsWifiMonitor::Onready(uint32_t count, nsIWifiScanResult **results)
+{
+ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+ LOG(("@@@@@ About to send data to the wifi listeners\n"));
+
+ nsCOMArray<nsWifiAccessPoint> accessPoints;
+
+ for (uint32_t i = 0; i < count; i++) {
+ RefPtr<nsWifiAccessPoint> ap = new nsWifiAccessPoint();
+
+ nsString temp;
+ results[i]->GetBssid(temp);
+ // 00:00:00:00:00:00 --> 00-00-00-00-00-00
+ for (int32_t x=0; x<6; x++) {
+ temp.ReplaceSubstring(NS_LITERAL_STRING(":"), NS_LITERAL_STRING("-")); // would it be too much to ask for a ReplaceAll()?
+ }
+
+ nsCString mac;
+ mac.AssignWithConversion(temp);
+
+ results[i]->GetSsid(temp);
+
+ nsCString ssid;
+ ssid.AssignWithConversion(temp);
+
+ uint32_t signal;
+ results[i]->GetSignalStrength(&signal);
+
+ ap->setSignal(signal);
+ ap->setMacRaw(mac.get());
+ ap->setSSIDRaw(ssid.get(), ssid.Length());
+
+ accessPoints.AppendObject(ap);
+ }
+
+ bool accessPointsChanged = !AccessPointsEqual(accessPoints, mLastAccessPoints);
+ ReplaceArray(mLastAccessPoints, accessPoints);
+
+ nsTArray<nsIWifiAccessPoint*> ac;
+ uint32_t resultCount = mLastAccessPoints.Count();
+ for (uint32_t i = 0; i < resultCount; i++) {
+ ac.AppendElement(mLastAccessPoints[i]);
+ }
+
+ for (uint32_t i = 0; i < mListeners.Length(); i++) {
+ if (!mListeners[i].mHasSentData || accessPointsChanged) {
+ mListeners[i].mHasSentData = true;
+ mListeners[i].mListener->OnChange(ac.Elements(), ac.Length());
+ }
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWifiMonitor::Onfailure()
+{
+ NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+ LOG(("@@@@@ About to send error to the wifi listeners\n"));
+ for (uint32_t i = 0; i < mListeners.Length(); i++) {
+ mListeners[i].mListener->OnError(NS_ERROR_UNEXPECTED);
+ }
+
+ ClearTimer();
+ return NS_OK;
+}
diff --git a/netwerk/wifi/nsWifiScannerDBus.cpp b/netwerk/wifi/nsWifiScannerDBus.cpp
new file mode 100644
index 000000000..182553e18
--- /dev/null
+++ b/netwerk/wifi/nsWifiScannerDBus.cpp
@@ -0,0 +1,337 @@
+/* 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 "nsWifiScannerDBus.h"
+#include "mozilla/ipc/DBusMessageRefPtr.h"
+#include "nsWifiAccessPoint.h"
+
+namespace mozilla {
+
+nsWifiScannerDBus::nsWifiScannerDBus(nsCOMArray<nsWifiAccessPoint> *aAccessPoints)
+: mAccessPoints(aAccessPoints)
+{
+ MOZ_ASSERT(mAccessPoints);
+
+ mConnection =
+ already_AddRefed<DBusConnection>(dbus_bus_get(DBUS_BUS_SYSTEM, nullptr));
+ MOZ_ASSERT(mConnection);
+ dbus_connection_set_exit_on_disconnect(mConnection, false);
+
+ MOZ_COUNT_CTOR(nsWifiScannerDBus);
+}
+
+nsWifiScannerDBus::~nsWifiScannerDBus()
+{
+ MOZ_COUNT_DTOR(nsWifiScannerDBus);
+}
+
+nsresult
+nsWifiScannerDBus::Scan()
+{
+ return SendMessage("org.freedesktop.NetworkManager",
+ "/org/freedesktop/NetworkManager",
+ "GetDevices");
+}
+
+nsresult
+nsWifiScannerDBus::SendMessage(const char* aInterface,
+ const char* aPath,
+ const char* aFuncCall)
+{
+ RefPtr<DBusMessage> msg = already_AddRefed<DBusMessage>(
+ dbus_message_new_method_call("org.freedesktop.NetworkManager",
+ aPath, aInterface, aFuncCall));
+ if (!msg) {
+ return NS_ERROR_FAILURE;
+ }
+
+ DBusMessageIter argsIter;
+ dbus_message_iter_init_append(msg, &argsIter);
+
+ if (!strcmp(aFuncCall, "Get")) {
+ const char* paramInterface = "org.freedesktop.NetworkManager.Device";
+ if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING,
+ &paramInterface)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ const char* paramDeviceType = "DeviceType";
+ if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING,
+ &paramDeviceType)) {
+ return NS_ERROR_FAILURE;
+ }
+ } else if (!strcmp(aFuncCall, "GetAll")) {
+ const char* param = "";
+ if (!dbus_message_iter_append_basic(&argsIter, DBUS_TYPE_STRING, &param)) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ DBusError err;
+ dbus_error_init(&err);
+
+ // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
+ // Refer to function dbus_connection_send_with_reply_and_block.
+ const uint32_t DBUS_DEFAULT_TIMEOUT = -1;
+ RefPtr<DBusMessage> reply = already_AddRefed<DBusMessage>(
+ dbus_connection_send_with_reply_and_block(mConnection, msg,
+ DBUS_DEFAULT_TIMEOUT, &err));
+ if (dbus_error_is_set(&err)) {
+ dbus_error_free(&err);
+
+ // In the GetAccessPoints case, if there are no access points, error is set.
+ // We don't want to error out here.
+ if (!strcmp(aFuncCall, "GetAccessPoints")) {
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+ }
+
+ nsresult rv;
+ if (!strcmp(aFuncCall, "GetDevices")) {
+ rv = IdentifyDevices(reply);
+ } else if (!strcmp(aFuncCall, "Get")) {
+ rv = IdentifyDeviceType(reply, aPath);
+ } else if (!strcmp(aFuncCall, "GetAccessPoints")) {
+ rv = IdentifyAccessPoints(reply);
+ } else if (!strcmp(aFuncCall, "GetAll")) {
+ rv = IdentifyAPProperties(reply);
+ } else {
+ rv = NS_ERROR_FAILURE;
+ }
+ return rv;
+}
+
+nsresult
+nsWifiScannerDBus::IdentifyDevices(DBusMessage* aMsg)
+{
+ DBusMessageIter iter;
+ nsresult rv = GetDBusIterator(aMsg, &iter);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ const char* devicePath;
+ do {
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) {
+ return NS_ERROR_FAILURE;
+ }
+
+ dbus_message_iter_get_basic(&iter, &devicePath);
+ if (!devicePath) {
+ return NS_ERROR_FAILURE;
+ }
+
+ rv = SendMessage("org.freedesktop.DBus.Properties", devicePath, "Get");
+ NS_ENSURE_SUCCESS(rv, rv);
+ } while (dbus_message_iter_next(&iter));
+
+ return NS_OK;
+}
+
+nsresult
+nsWifiScannerDBus::IdentifyDeviceType(DBusMessage* aMsg, const char* aDevicePath)
+{
+ DBusMessageIter args;
+ if (!dbus_message_iter_init(aMsg, &args)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_VARIANT) {
+ return NS_ERROR_FAILURE;
+ }
+
+ DBusMessageIter variantIter;
+ dbus_message_iter_recurse(&args, &variantIter);
+ if (dbus_message_iter_get_arg_type(&variantIter) != DBUS_TYPE_UINT32) {
+ return NS_ERROR_FAILURE;
+ }
+
+ uint32_t deviceType;
+ dbus_message_iter_get_basic(&variantIter, &deviceType);
+
+ // http://projects.gnome.org/NetworkManager/developers/api/07/spec-07.html
+ // Refer to NM_DEVICE_TYPE_WIFI under NM_DEVICE_TYPE.
+ const uint32_t NM_DEVICE_TYPE_WIFI = 2;
+ nsresult rv = NS_OK;
+ if (deviceType == NM_DEVICE_TYPE_WIFI) {
+ rv = SendMessage("org.freedesktop.NetworkManager.Device.Wireless",
+ aDevicePath, "GetAccessPoints");
+ }
+
+ return rv;
+}
+
+nsresult
+nsWifiScannerDBus::IdentifyAccessPoints(DBusMessage* aMsg)
+{
+ DBusMessageIter iter;
+ nsresult rv = GetDBusIterator(aMsg, &iter);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ const char* path;
+ do {
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) {
+ return NS_ERROR_FAILURE;
+ }
+ dbus_message_iter_get_basic(&iter, &path);
+ if (!path) {
+ return NS_ERROR_FAILURE;
+ }
+
+ rv = SendMessage("org.freedesktop.DBus.Properties", path, "GetAll");
+ NS_ENSURE_SUCCESS(rv, rv);
+ } while (dbus_message_iter_next(&iter));
+
+ return NS_OK;
+}
+
+nsresult
+nsWifiScannerDBus::IdentifyAPProperties(DBusMessage* aMsg)
+{
+ DBusMessageIter arr;
+ nsresult rv = GetDBusIterator(aMsg, &arr);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ RefPtr<nsWifiAccessPoint> ap = new nsWifiAccessPoint();
+ do {
+ DBusMessageIter dict;
+ dbus_message_iter_recurse(&arr, &dict);
+
+ do {
+ const char* key;
+ dbus_message_iter_get_basic(&dict, &key);
+ if (!key) {
+ return NS_ERROR_FAILURE;
+ }
+ dbus_message_iter_next(&dict);
+
+ DBusMessageIter variant;
+ dbus_message_iter_recurse(&dict, &variant);
+
+ if (!strncmp(key, "Ssid", strlen("Ssid"))) {
+ nsresult rv = StoreSsid(&variant, ap);
+ NS_ENSURE_SUCCESS(rv, rv);
+ break;
+ }
+
+ if (!strncmp(key, "HwAddress", strlen("HwAddress"))) {
+ nsresult rv = SetMac(&variant, ap);
+ NS_ENSURE_SUCCESS(rv, rv);
+ break;
+ }
+
+ if (!strncmp(key, "Strength", strlen("Strength"))) {
+ if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_BYTE) {
+ return NS_ERROR_FAILURE;
+ }
+
+ uint8_t strength;
+ dbus_message_iter_get_basic(&variant, &strength);
+ ap->setSignal(strength);
+ }
+ } while (dbus_message_iter_next(&dict));
+ } while (dbus_message_iter_next(&arr));
+
+ mAccessPoints->AppendObject(ap);
+ return NS_OK;
+}
+
+nsresult
+nsWifiScannerDBus::StoreSsid(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp)
+{
+ if (dbus_message_iter_get_arg_type(aVariant) != DBUS_TYPE_ARRAY) {
+ return NS_ERROR_FAILURE;
+ }
+
+ DBusMessageIter variantMember;
+ dbus_message_iter_recurse(aVariant, &variantMember);
+
+ const uint32_t MAX_SSID_LEN = 32;
+ char ssid[MAX_SSID_LEN];
+ memset(ssid, '\0', ArrayLength(ssid));
+ uint32_t i = 0;
+ do {
+ if (dbus_message_iter_get_arg_type(&variantMember) != DBUS_TYPE_BYTE) {
+ return NS_ERROR_FAILURE;
+ }
+
+ dbus_message_iter_get_basic(&variantMember, &ssid[i]);
+ i++;
+ } while (dbus_message_iter_next(&variantMember) && i < MAX_SSID_LEN);
+
+ aAp->setSSID(ssid, i);
+ return NS_OK;
+}
+
+nsresult
+nsWifiScannerDBus::SetMac(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp)
+{
+ if (dbus_message_iter_get_arg_type(aVariant) != DBUS_TYPE_STRING) {
+ return NS_ERROR_FAILURE;
+ }
+
+ // hwAddress format is XX:XX:XX:XX:XX:XX. Need to convert to XXXXXX format.
+ char* hwAddress;
+ dbus_message_iter_get_basic(aVariant, &hwAddress);
+ if (!hwAddress) {
+ return NS_ERROR_FAILURE;
+ }
+
+ const uint32_t MAC_LEN = 6;
+ uint8_t macAddress[MAC_LEN];
+ char* token = strtok(hwAddress, ":");
+ for (uint32_t i = 0; i < ArrayLength(macAddress); i++) {
+ if (!token) {
+ return NS_ERROR_FAILURE;
+ }
+ macAddress[i] = strtoul(token, nullptr, 16);
+ token = strtok(nullptr, ":");
+ }
+ aAp->setMac(macAddress);
+ return NS_OK;
+}
+
+nsresult
+nsWifiScannerDBus::GetDBusIterator(DBusMessage* aMsg,
+ DBusMessageIter* aIterArray)
+{
+ DBusMessageIter iter;
+ if (!dbus_message_iter_init(aMsg, &iter)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
+ return NS_ERROR_FAILURE;
+ }
+
+ dbus_message_iter_recurse(&iter, aIterArray);
+ return NS_OK;
+}
+
+} // mozilla
+
+nsresult
+nsWifiMonitor::DoScan()
+{
+ nsCOMArray<nsWifiAccessPoint> accessPoints;
+ mozilla::nsWifiScannerDBus wifiScanner(&accessPoints);
+ nsCOMArray<nsWifiAccessPoint> lastAccessPoints;
+
+ while (mKeepGoing) {
+ accessPoints.Clear();
+ nsresult rv = wifiScanner.Scan();
+ NS_ENSURE_SUCCESS(rv, rv);
+ bool accessPointsChanged = !AccessPointsEqual(accessPoints,
+ lastAccessPoints);
+ ReplaceArray(lastAccessPoints, accessPoints);
+
+ rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ LOG(("waiting on monitor\n"));
+ mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+ mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
+ }
+
+ return NS_OK;
+}
diff --git a/netwerk/wifi/nsWifiScannerDBus.h b/netwerk/wifi/nsWifiScannerDBus.h
new file mode 100644
index 000000000..516eb5ff2
--- /dev/null
+++ b/netwerk/wifi/nsWifiScannerDBus.h
@@ -0,0 +1,45 @@
+/* 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/. */
+
+#ifndef NSWIFIAPSCANNERDBUS_H_
+#define NSWIFIAPSCANNERDBUS_H_
+
+#include "nsCOMArray.h"
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus.h>
+
+#include "mozilla/ipc/DBusConnectionRefPtr.h"
+
+class nsWifiAccessPoint;
+
+namespace mozilla {
+
+class nsWifiScannerDBus final
+{
+public:
+ explicit nsWifiScannerDBus(nsCOMArray<nsWifiAccessPoint>* aAccessPoints);
+ ~nsWifiScannerDBus();
+
+ nsresult Scan();
+
+private:
+ nsresult SendMessage(const char* aInterface,
+ const char* aPath,
+ const char* aFuncCall);
+ nsresult IdentifyDevices(DBusMessage* aMsg);
+ nsresult IdentifyDeviceType(DBusMessage* aMsg, const char* aDevicePath);
+ nsresult IdentifyAccessPoints(DBusMessage* aMsg);
+ nsresult IdentifyAPProperties(DBusMessage* aMsg);
+ nsresult StoreSsid(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp);
+ nsresult SetMac(DBusMessageIter* aVariant, nsWifiAccessPoint* aAp);
+ nsresult GetDBusIterator(DBusMessage* aMsg, DBusMessageIter* aIterArray);
+
+ RefPtr<DBusConnection> mConnection;
+ nsCOMArray<nsWifiAccessPoint>* mAccessPoints;
+};
+
+} // mozilla
+
+#endif // NSWIFIAPSCANNERDBUS_H_
diff --git a/netwerk/wifi/nsWifiScannerFreeBSD.cpp b/netwerk/wifi/nsWifiScannerFreeBSD.cpp
new file mode 100644
index 000000000..4185d6989
--- /dev/null
+++ b/netwerk/wifi/nsWifiScannerFreeBSD.cpp
@@ -0,0 +1,171 @@
+/* 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/. */
+
+// Developed by J.R. Oldroyd <fbsd@opal.com>, December 2012.
+
+// For FreeBSD we use the getifaddrs(3) to obtain the list of interfaces
+// and then check for those with an 802.11 media type and able to return
+// a list of stations. This is similar to ifconfig(8).
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_media.h>
+#ifdef __DragonFly__
+#include <netproto/802_11/ieee80211_ioctl.h>
+#else
+#include <net80211/ieee80211_ioctl.h>
+#endif
+
+#include <ifaddrs.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nsWifiAccessPoint.h"
+
+using namespace mozilla;
+
+static nsresult
+FreeBSDGetAccessPointData(nsCOMArray<nsWifiAccessPoint> &accessPoints)
+{
+ // get list of interfaces
+ struct ifaddrs *ifal;
+ if (getifaddrs(&ifal) < 0) {
+ return NS_ERROR_FAILURE;
+ }
+
+ accessPoints.Clear();
+
+ // loop through the interfaces
+ nsresult rv = NS_ERROR_FAILURE;
+ struct ifaddrs *ifa;
+ for (ifa = ifal; ifa; ifa = ifa->ifa_next) {
+ // limit to one interface per address
+ if (ifa->ifa_addr->sa_family != AF_LINK) {
+ continue;
+ }
+
+ // store interface name in socket structure
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
+ ifr.ifr_addr.sa_family = AF_LOCAL;
+
+ // open socket to interface
+ int s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
+ if (s < 0) {
+ continue;
+ }
+
+ // clear interface media structure
+ struct ifmediareq ifmr;
+ memset(&ifmr, 0, sizeof(ifmr));
+ strncpy(ifmr.ifm_name, ifa->ifa_name, sizeof(ifmr.ifm_name));
+
+ // get interface media information
+ if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+ close(s);
+ continue;
+ }
+
+ // check interface is a WiFi interface
+ if (IFM_TYPE(ifmr.ifm_active) != IFM_IEEE80211) {
+ close(s);
+ continue;
+ }
+
+ // perform WiFi scan
+ struct ieee80211req i802r;
+ char iscanbuf[32*1024];
+ memset(&i802r, 0, sizeof(i802r));
+ strncpy(i802r.i_name, ifa->ifa_name, sizeof(i802r.i_name));
+ i802r.i_type = IEEE80211_IOC_SCAN_RESULTS;
+ i802r.i_data = iscanbuf;
+ i802r.i_len = sizeof(iscanbuf);
+ if (ioctl(s, SIOCG80211, &i802r) < 0) {
+ close(s);
+ continue;
+ }
+
+ // close socket
+ close(s);
+
+ // loop through WiFi networks and build geoloc-lookup structure
+ char *vsr = (char *) i802r.i_data;
+ unsigned len = i802r.i_len;
+ while (len >= sizeof(struct ieee80211req_scan_result)) {
+ struct ieee80211req_scan_result *isr =
+ (struct ieee80211req_scan_result *) vsr;
+
+ // determine size of this entry
+ char *id;
+ int idlen;
+ if (isr->isr_meshid_len) {
+ id = vsr + isr->isr_ie_off + isr->isr_ssid_len;
+ idlen = isr->isr_meshid_len;
+ } else {
+ id = vsr + isr->isr_ie_off;
+ idlen = isr->isr_ssid_len;
+ }
+
+ // copy network data
+ char ssid[IEEE80211_NWID_LEN+1];
+ strncpy(ssid, id, idlen);
+ ssid[idlen] = '\0';
+ nsWifiAccessPoint *ap = new nsWifiAccessPoint();
+ ap->setSSID(ssid, strlen(ssid));
+ ap->setMac(isr->isr_bssid);
+ ap->setSignal(isr->isr_rssi);
+ accessPoints.AppendObject(ap);
+ rv = NS_OK;
+
+ // log the data
+ LOG(( "FreeBSD access point: "
+ "SSID: %s, MAC: %02x-%02x-%02x-%02x-%02x-%02x, "
+ "Strength: %d, Channel: %dMHz\n",
+ ssid, isr->isr_bssid[0], isr->isr_bssid[1], isr->isr_bssid[2],
+ isr->isr_bssid[3], isr->isr_bssid[4], isr->isr_bssid[5],
+ isr->isr_rssi, isr->isr_freq));
+
+ // increment pointers
+ len -= isr->isr_len;
+ vsr += isr->isr_len;
+ }
+ }
+
+ freeifaddrs(ifal);
+
+ return rv;
+}
+
+nsresult
+nsWifiMonitor::DoScan()
+{
+ // Regularly get the access point data.
+
+ nsCOMArray<nsWifiAccessPoint> lastAccessPoints;
+ nsCOMArray<nsWifiAccessPoint> accessPoints;
+
+ do {
+ nsresult rv = FreeBSDGetAccessPointData(accessPoints);
+ if (NS_FAILED(rv))
+ return rv;
+
+ bool accessPointsChanged = !AccessPointsEqual(accessPoints, lastAccessPoints);
+ ReplaceArray(lastAccessPoints, accessPoints);
+
+ 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));
+ }
+ while (mKeepGoing);
+
+ return NS_OK;
+}
diff --git a/netwerk/wifi/nsWifiScannerMac.cpp b/netwerk/wifi/nsWifiScannerMac.cpp
new file mode 100644
index 000000000..b8ca682c2
--- /dev/null
+++ b/netwerk/wifi/nsWifiScannerMac.cpp
@@ -0,0 +1,55 @@
+/* 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 <mach-o/dyld.h>
+#include <dlfcn.h>
+#include <unistd.h>
+
+#include "osx_wifi.h"
+
+#include "nsAutoPtr.h"
+#include "nsCOMArray.h"
+#include "nsWifiMonitor.h"
+#include "nsWifiAccessPoint.h"
+
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIMutableArray.h"
+
+using namespace mozilla;
+
+// defined in osx_corewlan.mm
+// basically replaces accesspoints in the passed reference
+// it lives in a separate file so that we can use objective c.
+extern nsresult GetAccessPointsFromWLAN(nsCOMArray<nsWifiAccessPoint> &accessPoints);
+
+nsresult
+nsWifiMonitor::DoScan()
+{
+ // Regularly get the access point data.
+
+ nsCOMArray<nsWifiAccessPoint> lastAccessPoints;
+ nsCOMArray<nsWifiAccessPoint> accessPoints;
+
+ do {
+ nsresult rv = GetAccessPointsFromWLAN(accessPoints);
+ if (NS_FAILED(rv))
+ return rv;
+
+ bool accessPointsChanged = !AccessPointsEqual(accessPoints, lastAccessPoints);
+ ReplaceArray(lastAccessPoints, accessPoints);
+
+ 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));
+ }
+ while (mKeepGoing);
+
+ return NS_OK;
+}
diff --git a/netwerk/wifi/nsWifiScannerSolaris.cpp b/netwerk/wifi/nsWifiScannerSolaris.cpp
new file mode 100644
index 000000000..6fbfa0eb7
--- /dev/null
+++ b/netwerk/wifi/nsWifiScannerSolaris.cpp
@@ -0,0 +1,149 @@
+/* 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 "nsWifiMonitor.h"
+#include "nsWifiAccessPoint.h"
+
+#include "nsServiceManagerUtils.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIMutableArray.h"
+
+#include "plstr.h"
+#include <glib.h>
+
+#define DLADM_STRSIZE 256
+#define DLADM_SECTIONS 3
+
+using namespace mozilla;
+
+struct val_strength_t {
+ const char *strength_name;
+ int signal_value;
+};
+
+static val_strength_t strength_vals[] = {
+ { "very weak", -112 },
+ { "weak", -88 },
+ { "good", -68 },
+ { "very good", -40 },
+ { "excellent", -16 }
+};
+
+static nsWifiAccessPoint *
+do_parse_str(char *bssid_str, char *essid_str, char *strength)
+{
+ unsigned char mac_as_int[6] = { 0 };
+ sscanf(bssid_str, "%x:%x:%x:%x:%x:%x", &mac_as_int[0], &mac_as_int[1],
+ &mac_as_int[2], &mac_as_int[3], &mac_as_int[4], &mac_as_int[5]);
+
+ int signal = 0;
+ uint32_t strength_vals_count = sizeof(strength_vals) / sizeof (val_strength_t);
+ for (uint32_t i = 0; i < strength_vals_count; i++) {
+ if (!strncasecmp(strength, strength_vals[i].strength_name, DLADM_STRSIZE)) {
+ signal = strength_vals[i].signal_value;
+ break;
+ }
+ }
+
+ nsWifiAccessPoint *ap = new nsWifiAccessPoint();
+ if (ap) {
+ ap->setMac(mac_as_int);
+ ap->setSignal(signal);
+ ap->setSSID(essid_str, PL_strnlen(essid_str, DLADM_STRSIZE));
+ }
+ return ap;
+}
+
+static void
+do_dladm(nsCOMArray<nsWifiAccessPoint> &accessPoints)
+{
+ GError *err = nullptr;
+ char *sout = nullptr;
+ char *serr = nullptr;
+ int exit_status = 0;
+ char * dladm_args[] = { "/usr/bin/pfexec", "/usr/sbin/dladm",
+ "scan-wifi", "-p", "-o", "BSSID,ESSID,STRENGTH" };
+
+ gboolean rv = g_spawn_sync("/", dladm_args, nullptr, (GSpawnFlags)0, nullptr,
+ nullptr, &sout, &serr, &exit_status, &err);
+ if (rv && !exit_status) {
+ char wlan[DLADM_SECTIONS][DLADM_STRSIZE+1];
+ uint32_t section = 0;
+ uint32_t sout_scan = 0;
+ uint32_t wlan_put = 0;
+ bool escape = false;
+ nsWifiAccessPoint* ap;
+ char sout_char;
+ do {
+ sout_char = sout[sout_scan++];
+ if (escape) {
+ escape = false;
+ if (sout_char != '\0') {
+ wlan[section][wlan_put++] = sout_char;
+ continue;
+ }
+ }
+
+ if (sout_char =='\\') {
+ escape = true;
+ continue;
+ }
+
+ if (sout_char == ':') {
+ wlan[section][wlan_put] = '\0';
+ section++;
+ wlan_put = 0;
+ continue;
+ }
+
+ if ((sout_char == '\0') || (sout_char == '\n')) {
+ wlan[section][wlan_put] = '\0';
+ if (section == DLADM_SECTIONS - 1) {
+ ap = do_parse_str(wlan[0], wlan[1], wlan[2]);
+ if (ap) {
+ accessPoints.AppendObject(ap);
+ }
+ }
+ section = 0;
+ wlan_put = 0;
+ continue;
+ }
+
+ wlan[section][wlan_put++] = sout_char;
+
+ } while ((wlan_put <= DLADM_STRSIZE) && (section < DLADM_SECTIONS) &&
+ (sout_char != '\0'));
+ }
+
+ g_free(sout);
+ g_free(serr);
+}
+
+nsresult
+nsWifiMonitor::DoScan()
+{
+ // Regularly get the access point data.
+
+ nsCOMArray<nsWifiAccessPoint> lastAccessPoints;
+ nsCOMArray<nsWifiAccessPoint> accessPoints;
+
+ while (mKeepGoing) {
+
+ accessPoints.Clear();
+ do_dladm(accessPoints);
+
+ bool accessPointsChanged = !AccessPointsEqual(accessPoints, lastAccessPoints);
+ ReplaceArray(lastAccessPoints, accessPoints);
+
+ nsresult rv = CallWifiListeners(lastAccessPoints, accessPointsChanged);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ LOG(("waiting on monitor\n"));
+
+ ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+ mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
+ }
+
+ return NS_OK;
+}
diff --git a/netwerk/wifi/nsWifiScannerWin.cpp b/netwerk/wifi/nsWifiScannerWin.cpp
new file mode 100644
index 000000000..ef18706e4
--- /dev/null
+++ b/netwerk/wifi/nsWifiScannerWin.cpp
@@ -0,0 +1,77 @@
+/* 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 "nsWifiMonitor.h"
+
+// moz headers (alphabetical)
+#include "nsAutoPtr.h"
+#include "nsCOMArray.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIMutableArray.h"
+#include "nsServiceManagerUtils.h"
+#include "nsWifiAccessPoint.h"
+#include "win_wifiScanner.h"
+#include "win_xp_wifiScanner.h"
+#include "mozilla/WindowsVersion.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()
+{
+ if (!mWinWifiScanner) {
+ if (IsWin2003OrLater()) {
+ mWinWifiScanner = new WinWifiScanner();
+ LOG(("Using Windows 2003+ wifi scanner."));
+ } else {
+ mWinWifiScanner = new WinXPWifiScanner();
+ LOG(("Using Windows XP wifi scanner."));
+ }
+
+ 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();
+ nsresult rv = mWinWifiScanner->GetAccessPointsFromWLAN(accessPoints);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ bool accessPointsChanged = !AccessPointsEqual(accessPoints, lastAccessPoints);
+ ReplaceArray(lastAccessPoints, accessPoints);
+
+ 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);
+ if (mKeepGoing) {
+ mon.Wait(PR_SecondsToInterval(kDefaultWifiScanInterval));
+ }
+ }
+ while (mKeepGoing);
+
+ return NS_OK;
+}
diff --git a/netwerk/wifi/osx_corewlan.mm b/netwerk/wifi/osx_corewlan.mm
new file mode 100644
index 000000000..5cc96729a
--- /dev/null
+++ b/netwerk/wifi/osx_corewlan.mm
@@ -0,0 +1,108 @@
+/* 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/. */
+
+#import <Cocoa/Cocoa.h>
+#import <CoreWLAN/CoreWLAN.h>
+
+#include <dlfcn.h>
+#include <unistd.h>
+
+#include <objc/objc.h>
+#include <objc/objc-runtime.h>
+
+#include "nsObjCExceptions.h"
+#include "nsAutoPtr.h"
+#include "nsCOMArray.h"
+#include "nsWifiMonitor.h"
+#include "nsWifiAccessPoint.h"
+
+nsresult
+GetAccessPointsFromWLAN(nsCOMArray<nsWifiAccessPoint> &accessPoints)
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
+
+ accessPoints.Clear();
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ @try {
+ NSBundle * bundle = [[[NSBundle alloc] initWithPath:@"/System/Library/Frameworks/CoreWLAN.framework"] autorelease];
+ if (!bundle) {
+ [pool release];
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ Class CWI_class = [bundle classNamed:@"CWInterface"];
+ if (!CWI_class) {
+ [pool release];
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ id scanResult = [[CWI_class interface] scanForNetworksWithParameters:nil error:nil];
+ if (!scanResult) {
+ [pool release];
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ NSArray* scan = [NSMutableArray arrayWithArray:scanResult];
+ NSEnumerator *enumerator = [scan objectEnumerator];
+
+ while (id anObject = [enumerator nextObject]) {
+ auto* ap = new nsWifiAccessPoint();
+ if (!ap) {
+ [pool release];
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ // [CWInterface bssidData] is deprecated on OS X 10.7 and up. Which is
+ // is a pain, so we'll use it for as long as it's available.
+ unsigned char macData[6] = {0};
+ if ([anObject respondsToSelector:@selector(bssidData)]) {
+ NSData* data = [anObject bssidData];
+ if (data) {
+ memcpy(macData, [data bytes], 6);
+ }
+ } else {
+ // [CWInterface bssid] returns a string formatted "00:00:00:00:00:00".
+ NSString* macString = [anObject bssid];
+ if (macString && ([macString length] == 17)) {
+ for (NSUInteger i = 0; i < 6; ++i) {
+ NSString* part = [macString substringWithRange:NSMakeRange(i * 3, 2)];
+ NSScanner* scanner = [NSScanner scannerWithString:part];
+ unsigned int data = 0;
+ if (![scanner scanHexInt:&data]) {
+ data = 0;
+ }
+ macData[i] = (unsigned char) data;
+ }
+ }
+ }
+
+ // [CWInterface rssiValue] is available on OS X 10.7 and up (and
+ // [CWInterface rssi] is deprecated).
+ int signal = 0;
+ if ([anObject respondsToSelector:@selector(rssiValue)]) {
+ signal = (int) ((NSInteger) [anObject rssiValue]);
+ } else {
+ signal = [[anObject rssi] intValue];
+ }
+
+ ap->setMac(macData);
+ ap->setSignal(signal);
+ ap->setSSID([[anObject ssid] UTF8String], 32);
+
+ accessPoints.AppendObject(ap);
+ }
+ }
+ @catch(NSException*) {
+ [pool release];
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ [pool release];
+
+ return NS_OK;
+
+ NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NS_ERROR_NOT_AVAILABLE);
+}
diff --git a/netwerk/wifi/osx_wifi.h b/netwerk/wifi/osx_wifi.h
new file mode 100644
index 000000000..8a72a84e2
--- /dev/null
+++ b/netwerk/wifi/osx_wifi.h
@@ -0,0 +1,120 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// 3. Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// The contents of this file are taken from Apple80211.h from the iStumbler
+// project (http://www.istumbler.net). This project is released under the BSD
+// license with the following restrictions.
+//
+// Copyright (c) 02006, Alf Watt (alf@istumbler.net). All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// * Neither the name of iStumbler nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This is the reverse engineered header for the Apple80211 private framework.
+// The framework can be found at
+// /System/Library/PrivateFrameworks/Apple80211.framework.
+
+#ifndef GEARS_GEOLOCATION_OSX_WIFI_H__
+#define GEARS_GEOLOCATION_OSX_WIFI_H__
+
+#include <CoreFoundation/CoreFoundation.h>
+
+extern "C" {
+
+typedef SInt32 WIErr;
+
+// A WirelessContext should be created using WirelessAttach
+// before any other Wireless functions are called. WirelessDetach
+// is used to dispose of a WirelessContext.
+typedef struct __WirelessContext *WirelessContextPtr;
+
+// WirelessAttach
+//
+// This should be called before all other wireless functions.
+typedef WIErr (*WirelessAttachFunction)(WirelessContextPtr *outContext,
+ const UInt32);
+
+// WirelessDetach
+//
+// This should be called after all other wireless functions.
+typedef WIErr (*WirelessDetachFunction)(WirelessContextPtr inContext);
+
+typedef UInt16 WINetworkInfoFlags;
+
+struct WirelessNetworkInfo
+{
+ UInt16 channel; // Channel for the network.
+ SInt16 noise; // Noise for the network. 0 for Adhoc.
+ SInt16 signal; // Signal strength of the network. 0 for Adhoc.
+ UInt8 macAddress[6]; // MAC address of the wireless access point.
+ UInt16 beaconInterval; // Beacon interval in milliseconds
+ WINetworkInfoFlags flags; // Flags for the network
+ UInt16 nameLen;
+ SInt8 name[32];
+};
+
+// WirelessScanSplit
+//
+// WirelessScanSplit scans for available wireless networks. It will allocate 2
+// CFArrays to store a list of managed and adhoc networks. The arrays hold
+// CFData objects which contain WirelessNetworkInfo structures.
+//
+// Note: An adhoc network created on the computer the scan is running on will
+// not be found. WirelessGetInfo can be used to find info about a local adhoc
+// network.
+//
+// If stripDups != 0 only one bases tation for each SSID will be returned.
+typedef WIErr (*WirelessScanSplitFunction)(WirelessContextPtr inContext,
+ CFArrayRef *apList,
+ CFArrayRef *adhocList,
+ const UInt32 stripDups);
+
+} // extern "C"
+
+#endif // GEARS_GEOLOCATION_OSX_WIFI_H__
diff --git a/netwerk/wifi/tests/wifi_access_point_test.html b/netwerk/wifi/tests/wifi_access_point_test.html
new file mode 100644
index 000000000..974a6be15
--- /dev/null
+++ b/netwerk/wifi/tests/wifi_access_point_test.html
@@ -0,0 +1,60 @@
+<html>
+<head>
+<title>hi</title>
+<script>
+
+var count = 0;
+
+
+function test() {
+}
+
+test.prototype =
+{
+ onChange: function (accessPoints)
+ {
+ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+ var d = document.getElementById("d");
+ d.innerHTML = "";
+
+ for (var i=0; i<accessPoints.length; i++) {
+ var a = accessPoints[i];
+ d.innerHTML = d.innerHTML + "<p>" + a.mac + " " + a.ssid + " " + a.signal + "</p>";
+ }
+
+ var c = document.getElementById("c");
+ c.innerHTML = "<p>" + count++ + "</p>";
+
+ },
+
+ onError: function (value) {
+ alert("error: " +value);
+ },
+
+ QueryInterface: function(iid) {
+ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+ if (iid.equals(Components.interfaces.nsIWifiListener) ||
+ iid.equals(Components.interfaces.nsISupports))
+ return this;
+ throw Components.results.NS_ERROR_NO_INTERFACE;
+ },
+}
+
+
+ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+
+ var listener = new test();
+ var wifi_service = Components.classes["@mozilla.org/wifi/monitor;1"].getService(Components.interfaces.nsIWifiMonitor);
+
+ wifi_service.startWatching(listener);
+
+
+
+</script>
+</head>
+
+<body>
+<div id="d"><p></p></div>
+<div id="c"><p></p></div>
+</body>
+</html>
diff --git a/netwerk/wifi/win_wifiScanner.cpp b/netwerk/wifi/win_wifiScanner.cpp
new file mode 100644
index 000000000..a462b9696
--- /dev/null
+++ b/netwerk/wifi/win_wifiScanner.cpp
@@ -0,0 +1,195 @@
+/* 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 "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();
+ if (!mWlanLibrary) {
+ NS_WARNING("Could not initialize Windows Wi-Fi scanner");
+ }
+}
+
+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;
+}
diff --git a/netwerk/wifi/win_wifiScanner.h b/netwerk/wifi/win_wifiScanner.h
new file mode 100644
index 000000000..b43c23899
--- /dev/null
+++ b/netwerk/wifi/win_wifiScanner.h
@@ -0,0 +1,41 @@
+/* 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"
+#include "win_wlanLibrary.h"
+
+class nsWifiAccessPoint;
+
+// This class allows the wifi monitor to use WinWifiScanner and WinXPWifiScanner interchangeably.
+class WindowsWifiScannerInterface {
+public:
+ virtual ~WindowsWifiScannerInterface() {}
+
+ virtual nsresult GetAccessPointsFromWLAN(nsCOMArray<nsWifiAccessPoint> &accessPoints) = 0;
+};
+
+
+class WinWifiScanner : public WindowsWifiScannerInterface {
+ public:
+ WinWifiScanner();
+ virtual ~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;
+};
diff --git a/netwerk/wifi/win_wlanLibrary.cpp b/netwerk/wifi/win_wlanLibrary.cpp
new file mode 100644
index 000000000..cf1052788
--- /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;
+ }
+}
diff --git a/netwerk/wifi/win_wlanLibrary.h b/netwerk/wifi/win_wlanLibrary.h
new file mode 100644
index 000000000..3daf4618e
--- /dev/null
+++ b/netwerk/wifi/win_wlanLibrary.h
@@ -0,0 +1,61 @@
+/* -*- 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();
+ 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)
+ : mLibrary(library)
+ , mObject(object)
+ {
+ }
+
+ ~ScopedWLANObject()
+ {
+ (*(mLibrary->GetWlanFreeMemoryPtr()))(mObject);
+ }
+
+ private:
+ WinWLANLibrary *mLibrary;
+ void *mObject;
+};
diff --git a/netwerk/wifi/win_xp_wifiScanner.cpp b/netwerk/wifi/win_xp_wifiScanner.cpp
new file mode 100644
index 000000000..4dcd34034
--- /dev/null
+++ b/netwerk/wifi/win_xp_wifiScanner.cpp
@@ -0,0 +1,399 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Windows Vista uses the Native Wifi (WLAN) API for accessing WiFi cards. See
+// http://msdn.microsoft.com/en-us/library/ms705945(VS.85).aspx. Windows XP
+// Service Pack 3 (and Windows XP Service Pack 2, if upgraded with a hot fix)
+// also support a limited version of the WLAN API. See
+// http://msdn.microsoft.com/en-us/library/bb204766.aspx. The WLAN API uses
+// wlanapi.h, which is not part of the SDK used by Gears, so is replicated
+// locally using data from the MSDN.
+//\
+// Windows XP from Service Pack 2 onwards supports the Wireless Zero
+// Configuration (WZC) programming interface. See
+// http://msdn.microsoft.com/en-us/library/ms706587(VS.85).aspx.
+//
+// The MSDN recommends that one use the WLAN API where available, and WZC
+// otherwise.
+//
+// However, it seems that WZC fails for some wireless cards. Also, WLAN seems
+// not to work on XP SP3. So we use WLAN on Vista, and use NDIS directly
+// otherwise.
+
+// MOZILLA NOTE:
+// This code is ported from chromium:
+// https://chromium.googlesource.com/chromium/src/+/master/content/browser/geolocation/wifi_data_provider_win.cc
+// Based on changeset 42c5878
+
+#include "win_xp_wifiScanner.h"
+#include "nsWifiAccessPoint.h"
+#include <windows.h>
+#include <winioctl.h>
+#include <wlanapi.h>
+#include <string>
+#include <vector>
+
+// Taken from ndis.h for WinCE.
+#define NDIS_STATUS_INVALID_LENGTH ((NDIS_STATUS)0xC0010014L)
+#define NDIS_STATUS_BUFFER_TOO_SHORT ((NDIS_STATUS)0xC0010016L)
+
+namespace {
+// The limits on the size of the buffer used for the OID query.
+const int kInitialBufferSize = 2 << 12; // Good for about 50 APs.
+const int kMaximumBufferSize = 2 << 20; // 2MB
+
+// Length for generic string buffers passed to Win32 APIs.
+const int kStringLength = 512;
+
+// WlanOpenHandle
+typedef DWORD (WINAPI* WlanOpenHandleFunction)(DWORD dwClientVersion,
+ PVOID pReserved,
+ PDWORD pdwNegotiatedVersion,
+ PHANDLE phClientHandle);
+
+// WlanEnumInterfaces
+typedef DWORD (WINAPI* WlanEnumInterfacesFunction)(
+ HANDLE hClientHandle,
+ PVOID pReserved,
+ PWLAN_INTERFACE_INFO_LIST* ppInterfaceList);
+
+// WlanGetNetworkBssList
+typedef DWORD (WINAPI* WlanGetNetworkBssListFunction)(
+ HANDLE hClientHandle,
+ const GUID* pInterfaceGuid,
+ const PDOT11_SSID pDot11Ssid,
+ DOT11_BSS_TYPE dot11BssType,
+ BOOL bSecurityEnabled,
+ PVOID pReserved,
+ PWLAN_BSS_LIST* ppWlanBssList
+);
+
+// WlanFreeMemory
+typedef VOID (WINAPI* WlanFreeMemoryFunction)(PVOID pMemory);
+
+// WlanCloseHandle
+typedef DWORD (WINAPI* WlanCloseHandleFunction)(HANDLE hClientHandle,
+ PVOID pReserved);
+
+// Extracts data for an access point and converts to Gears format.
+bool UndefineDosDevice(const std::string& device_name);
+bool DefineDosDeviceIfNotExists(const std::string& device_name);
+HANDLE GetFileHandle(const std::string& device_name);
+// Makes the OID query and returns a Win32 error code.
+int PerformQuery(HANDLE adapter_handle, std::vector<char>& buffer, DWORD* bytes_out);
+bool ResizeBuffer(size_t requested_size, std::vector<char>& buffer);
+// Gets the system directory and appends a trailing slash if not already
+// present.
+bool GetSystemDirectory(std::string* path);
+
+bool ConvertToAccessPointData(const NDIS_WLAN_BSSID& data, nsWifiAccessPoint* access_point_data);
+int GetDataFromBssIdList(const NDIS_802_11_BSSID_LIST& bss_id_list,
+ int list_size,
+ nsCOMArray<nsWifiAccessPoint>& outData);
+} // namespace
+
+class WindowsNdisApi
+{
+public:
+ virtual ~WindowsNdisApi();
+ static WindowsNdisApi* Create();
+ virtual bool GetAccessPointData(nsCOMArray<nsWifiAccessPoint>& outData);
+
+private:
+ static bool GetInterfacesNDIS(std::vector<std::string>& interface_service_names_out);
+ // Swaps in content of the vector passed
+ explicit WindowsNdisApi(std::vector<std::string>* interface_service_names);
+ bool GetInterfaceDataNDIS(HANDLE adapter_handle, nsCOMArray<nsWifiAccessPoint>& outData);
+ // NDIS variables.
+ std::vector<std::string> interface_service_names_;
+ std::vector<char> _buffer;
+};
+
+// WindowsNdisApi
+WindowsNdisApi::WindowsNdisApi(
+ std::vector<std::string>* interface_service_names)
+ : _buffer(kInitialBufferSize) {
+ interface_service_names_.swap(*interface_service_names);
+}
+
+WindowsNdisApi::~WindowsNdisApi() {
+}
+
+WindowsNdisApi* WindowsNdisApi::Create() {
+ std::vector<std::string> interface_service_names;
+ if (GetInterfacesNDIS(interface_service_names)) {
+ return new WindowsNdisApi(&interface_service_names);
+ }
+ return NULL;
+}
+
+bool WindowsNdisApi::GetAccessPointData(nsCOMArray<nsWifiAccessPoint>& outData) {
+ int interfaces_failed = 0;
+ int interfaces_succeeded = 0;
+
+ for (int i = 0; i < static_cast<int>(interface_service_names_.size()); ++i) {
+ // First, check that we have a DOS device for this adapter.
+ if (!DefineDosDeviceIfNotExists(interface_service_names_[i])) {
+ continue;
+ }
+
+ // Get the handle to the device. This will fail if the named device is not
+ // valid.
+ HANDLE adapter_handle = GetFileHandle(interface_service_names_[i]);
+ if (adapter_handle == INVALID_HANDLE_VALUE) {
+ continue;
+ }
+
+ // Get the data.
+ if (GetInterfaceDataNDIS(adapter_handle, outData)) {
+ ++interfaces_succeeded;
+ } else {
+ ++interfaces_failed;
+ }
+
+ // Clean up.
+ CloseHandle(adapter_handle);
+ UndefineDosDevice(interface_service_names_[i]);
+ }
+
+ // Return true if at least one interface succeeded, or at the very least none
+ // failed.
+ return interfaces_succeeded > 0 || interfaces_failed == 0;
+}
+
+bool WindowsNdisApi::GetInterfacesNDIS(std::vector<std::string>& interface_service_names_out) {
+ HKEY network_cards_key = NULL;
+ if (RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ "Software\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards",
+ 0,
+ KEY_READ,
+ &network_cards_key) != ERROR_SUCCESS) {
+ return false;
+ }
+ if (!network_cards_key) {
+ return false;
+ }
+
+ for (int i = 0; ; ++i) {
+ TCHAR name[kStringLength];
+ DWORD name_size = kStringLength;
+ FILETIME time;
+ if (RegEnumKeyEx(network_cards_key,
+ i,
+ name,
+ &name_size,
+ NULL,
+ NULL,
+ NULL,
+ &time) != ERROR_SUCCESS) {
+ break;
+ }
+ HKEY hardware_key = NULL;
+ if (RegOpenKeyEx(network_cards_key, name, 0, KEY_READ, &hardware_key) !=
+ ERROR_SUCCESS) {
+ break;
+ }
+ if (!hardware_key) {
+ return false;
+ }
+
+ TCHAR service_name[kStringLength];
+ DWORD service_name_size = kStringLength;
+ DWORD type = 0;
+ if (RegQueryValueEx(hardware_key,
+ "ServiceName",
+ NULL,
+ &type,
+ reinterpret_cast<LPBYTE>(service_name),
+ &service_name_size) == ERROR_SUCCESS) {
+ interface_service_names_out.push_back(service_name);
+ }
+ RegCloseKey(hardware_key);
+ }
+
+ RegCloseKey(network_cards_key);
+ return true;
+}
+
+bool WindowsNdisApi::GetInterfaceDataNDIS(HANDLE adapter_handle,
+ nsCOMArray<nsWifiAccessPoint>& outData) {
+ DWORD bytes_out;
+ int result;
+
+ while (true) {
+ bytes_out = 0;
+ result = PerformQuery(adapter_handle, _buffer, &bytes_out);
+ if (result == ERROR_GEN_FAILURE || // Returned by some Intel cards.
+ result == ERROR_INSUFFICIENT_BUFFER ||
+ result == ERROR_MORE_DATA ||
+ result == NDIS_STATUS_INVALID_LENGTH ||
+ result == NDIS_STATUS_BUFFER_TOO_SHORT) {
+ // The buffer we supplied is too small, so increase it. bytes_out should
+ // provide the required buffer size, but this is not always the case.
+ size_t newSize;
+ if (bytes_out > static_cast<DWORD>(_buffer.size())) {
+ newSize = bytes_out;
+ } else {
+ newSize = _buffer.size() * 2;
+ }
+ if (!ResizeBuffer(newSize, _buffer)) {
+ return false;
+ }
+ } else {
+ // The buffer is not too small.
+ break;
+ }
+ }
+
+ if (result == ERROR_SUCCESS) {
+ NDIS_802_11_BSSID_LIST* bssid_list =
+ reinterpret_cast<NDIS_802_11_BSSID_LIST*>(&_buffer[0]);
+ GetDataFromBssIdList(*bssid_list, _buffer.size(), outData);
+ }
+
+ return true;
+}
+
+namespace {
+#define uint8 unsigned char
+
+bool ConvertToAccessPointData(const NDIS_WLAN_BSSID& data, nsWifiAccessPoint* access_point_data)
+{
+ access_point_data->setMac(data.MacAddress);
+ access_point_data->setSignal(data.Rssi);
+ // Note that _NDIS_802_11_SSID::Ssid::Ssid is not null-terminated.
+ const unsigned char* ssid = data.Ssid.Ssid;
+ size_t len = data.Ssid.SsidLength;
+ access_point_data->setSSID(reinterpret_cast<const char*>(ssid), len);
+ return true;
+}
+
+int GetDataFromBssIdList(const NDIS_802_11_BSSID_LIST& bss_id_list,
+ int list_size,
+ nsCOMArray<nsWifiAccessPoint>& outData)
+{
+ // Walk through the BSS IDs.
+ int found = 0;
+ const uint8* iterator = reinterpret_cast<const uint8*>(&bss_id_list.Bssid[0]);
+ const uint8* end_of_buffer =
+ reinterpret_cast<const uint8*>(&bss_id_list) + list_size;
+ for (int i = 0; i < static_cast<int>(bss_id_list.NumberOfItems); ++i) {
+ const NDIS_WLAN_BSSID *bss_id =
+ reinterpret_cast<const NDIS_WLAN_BSSID*>(iterator);
+ // Check that the length of this BSS ID is reasonable.
+ if (bss_id->Length < sizeof(NDIS_WLAN_BSSID) ||
+ iterator + bss_id->Length > end_of_buffer) {
+ break;
+ }
+ nsWifiAccessPoint* ap = new nsWifiAccessPoint();
+ if (ConvertToAccessPointData(*bss_id, ap)) {
+ outData.AppendObject(ap);
+ ++found;
+ }
+ // Move to the next BSS ID.
+ iterator += bss_id->Length;
+ }
+ return found;
+}
+
+
+bool UndefineDosDevice(const std::string& device_name) {
+ // We remove only the mapping we use, that is \Device\<device_name>.
+ std::string target_path = "\\Device\\" + device_name;
+ return DefineDosDevice(
+ DDD_RAW_TARGET_PATH | DDD_REMOVE_DEFINITION | DDD_EXACT_MATCH_ON_REMOVE,
+ device_name.c_str(),
+ target_path.c_str()) == TRUE;
+}
+
+bool DefineDosDeviceIfNotExists(const std::string& device_name) {
+ // We create a DOS device name for the device at \Device\<device_name>.
+ std::string target_path = "\\Device\\" + device_name;
+
+ TCHAR target[kStringLength];
+ if (QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
+ target_path.compare(target) == 0) {
+ // Device already exists.
+ return true;
+ }
+
+ if (GetLastError() != ERROR_FILE_NOT_FOUND) {
+ return false;
+ }
+
+ if (!DefineDosDevice(DDD_RAW_TARGET_PATH,
+ device_name.c_str(),
+ target_path.c_str())) {
+ return false;
+ }
+
+ // Check that the device is really there.
+ return QueryDosDevice(device_name.c_str(), target, kStringLength) > 0 &&
+ target_path.compare(target) == 0;
+}
+
+HANDLE GetFileHandle(const std::string& device_name) {
+ // We access a device with DOS path \Device\<device_name> at
+ // \\.\<device_name>.
+ std::string formatted_device_name = "\\\\.\\" + device_name;
+
+ return CreateFile(formatted_device_name.c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // share mode
+ 0, // security attributes
+ OPEN_EXISTING,
+ 0, // flags and attributes
+ INVALID_HANDLE_VALUE);
+}
+
+int PerformQuery(HANDLE adapter_handle,
+ std::vector<char>& buffer,
+ DWORD* bytes_out) {
+ DWORD oid = OID_802_11_BSSID_LIST;
+ if (!DeviceIoControl(adapter_handle,
+ IOCTL_NDIS_QUERY_GLOBAL_STATS,
+ &oid,
+ sizeof(oid),
+ &buffer[0],
+ buffer.size(),
+ bytes_out,
+ NULL)) {
+ return GetLastError();
+ }
+ return ERROR_SUCCESS;
+}
+
+bool ResizeBuffer(size_t requested_size, std::vector<char>& buffer) {
+ if (requested_size > kMaximumBufferSize) {
+ buffer.resize(kInitialBufferSize);
+ return false;
+ }
+
+ buffer.resize(requested_size);
+ return true;
+}
+
+} // namespace
+
+
+nsresult
+WinXPWifiScanner::GetAccessPointsFromWLAN(nsCOMArray<nsWifiAccessPoint> &accessPoints)
+{
+ if (!mImplementation) {
+ mImplementation = WindowsNdisApi::Create();
+ if (!mImplementation) {
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ accessPoints.Clear();
+ bool isOk = mImplementation->GetAccessPointData(accessPoints);
+ if (!isOk) {
+ mImplementation = 0;
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
diff --git a/netwerk/wifi/win_xp_wifiScanner.h b/netwerk/wifi/win_xp_wifiScanner.h
new file mode 100644
index 000000000..33ae4cae4
--- /dev/null
+++ b/netwerk/wifi/win_xp_wifiScanner.h
@@ -0,0 +1,25 @@
+/* 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/. */
+
+#ifndef WINXPWIFISCANNER_H_
+#define WINXPWIFISCANNER_H_
+
+#include "nsAutoPtr.h"
+#include "nsCOMArray.h"
+#include "win_wifiScanner.h"
+
+class nsWifiAccessPoint;
+class WindowsNdisApi;
+
+// This class is wrapper into the Chromium WindowNdisApi class for scanning wifis
+// on Windows XP. When Firefox drops XP support, this code can go.
+class WinXPWifiScanner : public WindowsWifiScannerInterface {
+public:
+ nsresult GetAccessPointsFromWLAN(nsCOMArray<nsWifiAccessPoint> &accessPoints);
+ virtual ~WinXPWifiScanner() {}
+private:
+ nsAutoPtr<WindowsNdisApi> mImplementation;
+};
+
+#endif \ No newline at end of file