123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- /* 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;
- }
|