tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WinWifiScanner.cpp (7638B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "nsWifiAccessPoint.h"
      6 #include "WinWifiScanner.h"
      7 
      8 #define DOT11_BSS_TYPE_UNUSED static_cast<DOT11_BSS_TYPE>(0)
      9 
     10 namespace mozilla {
     11 
     12 LazyLogModule gWifiScannerLog("WifiScanner");
     13 #define WIFISCAN_LOG(args) \
     14  MOZ_LOG(mozilla::gWifiScannerLog, mozilla::LogLevel::Debug, args)
     15 
     16 class InterfaceScanCallbackData {
     17 public:
     18  explicit InterfaceScanCallbackData(uint32_t numInterfaces)
     19      : mCurrentlyScanningInterfaces(numInterfaces) {
     20    mAllInterfacesDoneScanningEvent =
     21        ::CreateEventW(nullptr,   // null security
     22                       TRUE,      // manual reset event
     23                       FALSE,     // initially nonsignaled
     24                       nullptr);  // not named
     25    MOZ_ASSERT(NULL != mAllInterfacesDoneScanningEvent);
     26  }
     27 
     28  ~InterfaceScanCallbackData() {
     29    ::CloseHandle(mAllInterfacesDoneScanningEvent);
     30  }
     31 
     32  void OnInterfaceScanComplete() {
     33    uint32_t val = ::InterlockedDecrement(&mCurrentlyScanningInterfaces);
     34    if (!val) {
     35      ::SetEvent(mAllInterfacesDoneScanningEvent);
     36    }
     37  }
     38 
     39  void WaitForAllInterfacesToFinishScanning(uint32_t msToWait) {
     40    ::WaitForSingleObject(mAllInterfacesDoneScanningEvent, msToWait);
     41  }
     42 
     43 private:
     44  volatile uint32_t mCurrentlyScanningInterfaces;
     45  HANDLE mAllInterfacesDoneScanningEvent;
     46 };
     47 
     48 static void WINAPI OnScanComplete(PWLAN_NOTIFICATION_DATA data, PVOID context) {
     49  WIFISCAN_LOG(("WinWifiScanner OnScanComplete"));
     50  if (WLAN_NOTIFICATION_SOURCE_ACM != data->NotificationSource) {
     51    return;
     52  }
     53 
     54  if (wlan_notification_acm_scan_complete != data->NotificationCode &&
     55      wlan_notification_acm_scan_fail != data->NotificationCode) {
     56    return;
     57  }
     58 
     59  InterfaceScanCallbackData* cbData =
     60      reinterpret_cast<InterfaceScanCallbackData*>(context);
     61  cbData->OnInterfaceScanComplete();
     62 }
     63 
     64 WifiScannerImpl::WifiScannerImpl() {
     65  // NOTE: We assume that, if we were unable to load the WLAN library when
     66  // we initially tried, we will not be able to load it in the future.
     67  // Technically, on Windows XP SP2, a user could install the redistributable
     68  // and make our assumption incorrect. We opt to avoid making a bunch of
     69  // spurious LoadLibrary calls in the common case rather than load the
     70  // WLAN API in the edge case.
     71  mWlanLibrary.reset(WinWLANLibrary::Load());
     72  if (!mWlanLibrary) {
     73    WIFISCAN_LOG(
     74        ("[%p] WinWifiScanner could not initialize Windows Wi-Fi scanner",
     75         this));
     76  }
     77  WIFISCAN_LOG(("[%p] WinWifiScanner created WifiScannerImpl", this));
     78 }
     79 
     80 WifiScannerImpl::~WifiScannerImpl() {
     81  WIFISCAN_LOG(("[%p] WinWifiScanner destroyed WifiScannerImpl", this));
     82 }
     83 
     84 nsresult WifiScannerImpl::GetAccessPointsFromWLAN(
     85    nsTArray<RefPtr<nsIWifiAccessPoint>>& accessPoints) {
     86  WIFISCAN_LOG(("[%p] WinWifiScanner::GetAccessPointsFromWLAN", this));
     87  accessPoints.Clear();
     88 
     89  // NOTE: We do not try to load the WLAN library if we previously failed
     90  // to load it. See the note in WifiScannerImpl constructor
     91  if (!mWlanLibrary) {
     92    WIFISCAN_LOG(
     93        ("[%p] WinWifiScanner::GetAccessPointsFromWLAN WLAN library is not "
     94         "available",
     95         this));
     96    return NS_ERROR_NOT_AVAILABLE;
     97  }
     98 
     99  // Get the list of interfaces. WlanEnumInterfaces allocates interface_list.
    100  WLAN_INTERFACE_INFO_LIST* interface_list = nullptr;
    101  if (ERROR_SUCCESS !=
    102      (*mWlanLibrary->GetWlanEnumInterfacesPtr())(mWlanLibrary->GetWLANHandle(),
    103                                                  nullptr, &interface_list)) {
    104    WIFISCAN_LOG(
    105        ("[%p] WinWifiScanner::GetAccessPointsFromWLAN WlanEnumInterfaces "
    106         "failed",
    107         this));
    108    return NS_ERROR_FAILURE;
    109  }
    110 
    111  // This ensures we call WlanFreeMemory on interface_list
    112  ScopedWLANObject scopedInterfaceList(*mWlanLibrary, interface_list);
    113  WIFISCAN_LOG(
    114      ("[%p] WinWifiScanner::GetAccessPointsFromWLAN found %lu interfaces",
    115       this, interface_list->dwNumberOfItems));
    116 
    117  if (!interface_list->dwNumberOfItems) {
    118    return NS_OK;
    119  }
    120 
    121  InterfaceScanCallbackData cbData(interface_list->dwNumberOfItems);
    122 
    123  DWORD wlanNotifySource;
    124  if (ERROR_SUCCESS != (*mWlanLibrary->GetWlanRegisterNotificationPtr())(
    125                           mWlanLibrary->GetWLANHandle(),
    126                           WLAN_NOTIFICATION_SOURCE_ACM, TRUE,
    127                           (WLAN_NOTIFICATION_CALLBACK)OnScanComplete, &cbData,
    128                           NULL, &wlanNotifySource)) {
    129    WIFISCAN_LOG(
    130        ("[%p] WinWifiScanner::GetAccessPointsFromWLAN "
    131         "WlanRegisterNotification failed",
    132         this));
    133    return NS_ERROR_FAILURE;
    134  }
    135 
    136  // Go through the list of interfaces and call `WlanScan` on each
    137  for (unsigned int i = 0; i < interface_list->dwNumberOfItems; ++i) {
    138    if (ERROR_SUCCESS != (*mWlanLibrary->GetWlanScanPtr())(
    139                             mWlanLibrary->GetWLANHandle(),
    140                             &interface_list->InterfaceInfo[i].InterfaceGuid,
    141                             NULL, NULL, NULL)) {
    142      WIFISCAN_LOG(
    143          ("[%p] WinWifiScanner::GetAccessPointsFromWLAN WlanScan failed.",
    144           this));
    145      cbData.OnInterfaceScanComplete();
    146    }
    147  }
    148 
    149  // From the MSDN documentation:
    150  //   "Wireless network drivers that meet Windows logo requirements are
    151  // required to complete a WlanScan function request in 4 seconds"
    152  cbData.WaitForAllInterfacesToFinishScanning(5000);
    153 
    154  // Unregister for the notifications. The documentation mentions that,
    155  // if a callback is currently running, this will wait for the callback
    156  // to complete.
    157  (*mWlanLibrary->GetWlanRegisterNotificationPtr())(
    158      mWlanLibrary->GetWLANHandle(), WLAN_NOTIFICATION_SOURCE_NONE, TRUE, NULL,
    159      NULL, NULL, &wlanNotifySource);
    160 
    161  // Go through the list of interfaces and get the data for each.
    162  for (uint32_t i = 0; i < interface_list->dwNumberOfItems; ++i) {
    163    WLAN_BSS_LIST* bss_list;
    164    if (ERROR_SUCCESS != (*mWlanLibrary->GetWlanGetNetworkBssListPtr())(
    165                             mWlanLibrary->GetWLANHandle(),
    166                             &interface_list->InterfaceInfo[i].InterfaceGuid,
    167                             nullptr,  // Use all SSIDs.
    168                             DOT11_BSS_TYPE_UNUSED,
    169                             false,    // bSecurityEnabled -
    170                                       // unused
    171                             nullptr,  // reserved
    172                             &bss_list)) {
    173      WIFISCAN_LOG(
    174          ("[%p] WinWifiScanner::GetAccessPointsFromWLAN unable to get BSS "
    175           "list from interface %u",
    176           this, i));
    177      continue;
    178    }
    179 
    180    WIFISCAN_LOG(
    181        ("[%p] WinWifiScanner::GetAccessPointsFromWLAN BSS list has %lu access "
    182         "points",
    183         this, bss_list->dwNumberOfItems));
    184 
    185    // This ensures we call WlanFreeMemory on bss_list
    186    ScopedWLANObject scopedBssList(*mWlanLibrary, bss_list);
    187 
    188    // Store each discovered access point in our outparam
    189    for (int j = 0; j < static_cast<int>(bss_list->dwNumberOfItems); ++j) {
    190      nsWifiAccessPoint* ap = new nsWifiAccessPoint();
    191      if (!ap) {
    192        continue;
    193      }
    194 
    195      const WLAN_BSS_ENTRY bss_entry = bss_list->wlanBssEntries[j];
    196      ap->setMac(bss_entry.dot11Bssid);
    197      ap->setSignal(bss_entry.lRssi);
    198      ap->setSSID(reinterpret_cast<char const*>(bss_entry.dot11Ssid.ucSSID),
    199                  bss_entry.dot11Ssid.uSSIDLength);
    200 
    201      accessPoints.AppendElement(ap);
    202    }
    203  }
    204 
    205  return NS_OK;
    206 }
    207 
    208 }  // namespace mozilla
    209 
    210 #undef WIFISCAN_LOG