Home | History | Annotate | Download | only in scanning
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "wificond/scanning/scan_utils.h"
     18 
     19 #include <vector>
     20 
     21 #include <linux/netlink.h>
     22 #include <linux/nl80211.h>
     23 
     24 #include <android-base/logging.h>
     25 
     26 #include "wificond/net/netlink_manager.h"
     27 #include "wificond/net/nl80211_packet.h"
     28 #include "wificond/scanning/scan_result.h"
     29 
     30 using com::android::server::wifi::wificond::NativeScanResult;
     31 using std::unique_ptr;
     32 using std::vector;
     33 
     34 namespace android {
     35 namespace wificond {
     36 namespace {
     37 
     38 constexpr uint8_t kElemIdSsid = 0;
     39 constexpr unsigned int kMsecPerSec = 1000;
     40 
     41 }  // namespace
     42 
     43 ScanUtils::ScanUtils(NetlinkManager* netlink_manager)
     44     : netlink_manager_(netlink_manager) {
     45   if (!netlink_manager_->IsStarted()) {
     46     netlink_manager_->Start();
     47   }
     48 }
     49 
     50 ScanUtils::~ScanUtils() {}
     51 
     52 void ScanUtils::SubscribeScanResultNotification(
     53     uint32_t interface_index,
     54     OnScanResultsReadyHandler handler) {
     55   netlink_manager_->SubscribeScanResultNotification(interface_index, handler);
     56 }
     57 
     58 void ScanUtils::UnsubscribeScanResultNotification(uint32_t interface_index) {
     59   netlink_manager_->UnsubscribeScanResultNotification(interface_index);
     60 }
     61 
     62 void ScanUtils::SubscribeSchedScanResultNotification(
     63     uint32_t interface_index,
     64     OnSchedScanResultsReadyHandler handler) {
     65   netlink_manager_->SubscribeSchedScanResultNotification(interface_index,
     66                                                          handler);
     67 }
     68 
     69 void ScanUtils::UnsubscribeSchedScanResultNotification(
     70     uint32_t interface_index) {
     71   netlink_manager_->UnsubscribeSchedScanResultNotification(interface_index);
     72 }
     73 
     74 bool ScanUtils::GetScanResult(uint32_t interface_index,
     75                               vector<NativeScanResult>* out_scan_results) {
     76   NL80211Packet get_scan(
     77       netlink_manager_->GetFamilyId(),
     78       NL80211_CMD_GET_SCAN,
     79       netlink_manager_->GetSequenceNumber(),
     80       getpid());
     81   get_scan.AddFlag(NLM_F_DUMP);
     82   NL80211Attr<uint32_t> ifindex(NL80211_ATTR_IFINDEX, interface_index);
     83   get_scan.AddAttribute(ifindex);
     84 
     85   vector<unique_ptr<const NL80211Packet>> response;
     86   if (!netlink_manager_->SendMessageAndGetResponses(get_scan, &response))  {
     87     LOG(ERROR) << "NL80211_CMD_GET_SCAN dump failed";
     88     return false;
     89   }
     90   if (response.empty()) {
     91     LOG(INFO) << "Unexpected empty scan result!";
     92     return true;
     93   }
     94 
     95   for (auto& packet : response) {
     96     if (packet->GetMessageType() == NLMSG_ERROR) {
     97       LOG(ERROR) << "Receive ERROR message: "
     98                  << strerror(packet->GetErrorCode());
     99       continue;
    100     }
    101     if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) {
    102       LOG(ERROR) << "Wrong message type: "
    103                  << packet->GetMessageType();
    104       continue;
    105     }
    106     uint32_t if_index;
    107     if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
    108       LOG(ERROR) << "No interface index in scan result.";
    109       continue;
    110     }
    111     if (if_index != interface_index) {
    112       LOG(WARNING) << "Uninteresting scan result for interface: " << if_index;
    113       continue;
    114     }
    115 
    116     NativeScanResult scan_result;
    117     if (!ParseScanResult(std::move(packet), &scan_result)) {
    118       LOG(DEBUG) << "Ignore invalid scan result";
    119       continue;
    120     }
    121     out_scan_results->push_back(std::move(scan_result));
    122   }
    123   return true;
    124 }
    125 
    126 bool ScanUtils::ParseScanResult(unique_ptr<const NL80211Packet> packet,
    127                                 NativeScanResult* scan_result) {
    128   if (packet->GetCommand() != NL80211_CMD_NEW_SCAN_RESULTS) {
    129     LOG(ERROR) << "Wrong command command for new scan result message";
    130     return false;
    131   }
    132   NL80211NestedAttr bss(0);
    133   if (packet->GetAttribute(NL80211_ATTR_BSS, &bss)) {
    134     vector<uint8_t> bssid;
    135     if (!bss.GetAttributeValue(NL80211_BSS_BSSID, &bssid)) {
    136       LOG(ERROR) << "Failed to get BSSID from scan result packet";
    137       return false;
    138     }
    139     uint32_t freq;
    140     if (!bss.GetAttributeValue(NL80211_BSS_FREQUENCY, &freq)) {
    141       LOG(ERROR) << "Failed to get Frequency from scan result packet";
    142       return false;
    143     }
    144     vector<uint8_t> ie;
    145     if (!bss.GetAttributeValue(NL80211_BSS_INFORMATION_ELEMENTS, &ie)) {
    146       LOG(ERROR) << "Failed to get Information Element from scan result packet";
    147       return false;
    148     }
    149     vector<uint8_t> ssid;
    150     if (!GetSSIDFromInfoElement(ie, &ssid)) {
    151       // Skip BSS without SSID IE.
    152       // These scan results are considered as malformed.
    153       return false;
    154     }
    155     uint64_t last_seen_since_boot_microseconds;
    156     if (!GetBssTimestamp(bss, &last_seen_since_boot_microseconds)) {
    157       // Logging is done inside |GetBssTimestamp|.
    158       return false;
    159     }
    160     int32_t signal;
    161     if (!bss.GetAttributeValue(NL80211_BSS_SIGNAL_MBM, &signal)) {
    162       LOG(ERROR) << "Failed to get Signal Strength from scan result packet";
    163       return false;
    164     }
    165     uint16_t capability;
    166     if (!bss.GetAttributeValue(NL80211_BSS_CAPABILITY, &capability)) {
    167       LOG(ERROR) << "Failed to get capability field from scan result packet";
    168       return false;
    169     }
    170     bool associated = false;
    171     uint32_t bss_status;
    172     if (bss.GetAttributeValue(NL80211_BSS_STATUS, &bss_status) &&
    173             (bss_status == NL80211_BSS_STATUS_AUTHENTICATED ||
    174                 bss_status == NL80211_BSS_STATUS_ASSOCIATED)) {
    175       associated = true;
    176     }
    177 
    178     *scan_result =
    179         NativeScanResult(ssid, bssid, ie, freq, signal,
    180                          last_seen_since_boot_microseconds,
    181                          capability, associated);
    182   }
    183   return true;
    184 }
    185 
    186 bool ScanUtils::GetBssTimestampForTesting(
    187     const NL80211NestedAttr& bss,
    188     uint64_t* last_seen_since_boot_microseconds){
    189   return GetBssTimestamp(bss, last_seen_since_boot_microseconds);
    190 }
    191 
    192 bool ScanUtils::GetBssTimestamp(const NL80211NestedAttr& bss,
    193                                 uint64_t* last_seen_since_boot_microseconds){
    194   uint64_t last_seen_since_boot_nanoseconds;
    195   if (bss.GetAttributeValue(NL80211_BSS_LAST_SEEN_BOOTTIME,
    196                             &last_seen_since_boot_nanoseconds)) {
    197     *last_seen_since_boot_microseconds = last_seen_since_boot_nanoseconds / 1000;
    198   } else {
    199     // Fall back to use TSF if we can't find NL80211_BSS_LAST_SEEN_BOOTTIME
    200     // attribute.
    201     if (!bss.GetAttributeValue(NL80211_BSS_TSF, last_seen_since_boot_microseconds)) {
    202       LOG(ERROR) << "Failed to get TSF from scan result packet";
    203       return false;
    204     }
    205     uint64_t beacon_tsf_microseconds;
    206     if (bss.GetAttributeValue(NL80211_BSS_BEACON_TSF, &beacon_tsf_microseconds)) {
    207       *last_seen_since_boot_microseconds = std::max(*last_seen_since_boot_microseconds,
    208                                                     beacon_tsf_microseconds);
    209     }
    210   }
    211   return true;
    212 }
    213 
    214 bool ScanUtils::GetSSIDFromInfoElement(const vector<uint8_t>& ie,
    215                                        vector<uint8_t>* ssid) {
    216   // Information elements are stored in 'TLV' format.
    217   // Field:  |   Type     |          Length           |      Value      |
    218   // Length: |     1      |             1             |     variable    |
    219   // Content:| Element ID | Length of the Value field | Element payload |
    220   const uint8_t* end = ie.data() + ie.size();
    221   const uint8_t* ptr = ie.data();
    222   // +1 means we must have space for the length field.
    223   while (ptr + 1  < end) {
    224     uint8_t type = *ptr;
    225     uint8_t length = *(ptr + 1);
    226     // Length field is invalid.
    227     if (ptr + 1 + length >= end) {
    228       return false;
    229     }
    230     // SSID element is found.
    231     if (type == kElemIdSsid) {
    232       // SSID is an empty string.
    233       if (length == 0) {
    234         *ssid = vector<uint8_t>();
    235       } else {
    236         *ssid = vector<uint8_t>(ptr + 2, ptr + length + 2);
    237       }
    238       return true;
    239     }
    240     ptr += 2 + length;
    241   }
    242   return false;
    243 }
    244 
    245 bool ScanUtils::Scan(uint32_t interface_index,
    246                      bool request_random_mac,
    247                      const vector<vector<uint8_t>>& ssids,
    248                      const vector<uint32_t>& freqs,
    249                      int* error_code) {
    250   NL80211Packet trigger_scan(
    251       netlink_manager_->GetFamilyId(),
    252       NL80211_CMD_TRIGGER_SCAN,
    253       netlink_manager_->GetSequenceNumber(),
    254       getpid());
    255   // If we do not use NLM_F_ACK, we only receive a unicast repsonse
    256   // when there is an error. If everything is good, scan results notification
    257   // will only be sent through multicast.
    258   // If NLM_F_ACK is set, there will always be an unicast repsonse, either an
    259   // ERROR or an ACK message. The handler will always be called and removed by
    260   // NetlinkManager.
    261   trigger_scan.AddFlag(NLM_F_ACK);
    262   NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, interface_index);
    263 
    264   NL80211NestedAttr ssids_attr(NL80211_ATTR_SCAN_SSIDS);
    265   for (size_t i = 0; i < ssids.size(); i++) {
    266     ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, ssids[i]));
    267   }
    268   NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES);
    269   for (size_t i = 0; i < freqs.size(); i++) {
    270     freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i]));
    271   }
    272 
    273   trigger_scan.AddAttribute(if_index_attr);
    274   trigger_scan.AddAttribute(ssids_attr);
    275   // An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to
    276   // scan all supported frequencies.
    277   if (!freqs.empty()) {
    278     trigger_scan.AddAttribute(freqs_attr);
    279   }
    280 
    281   if (request_random_mac) {
    282     trigger_scan.AddAttribute(
    283         NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,
    284                               NL80211_SCAN_FLAG_RANDOM_ADDR));
    285   }
    286   // We are receiving an ERROR/ACK message instead of the actual
    287   // scan results here, so it is OK to expect a timely response because
    288   // kernel is supposed to send the ERROR/ACK back before the scan starts.
    289   vector<unique_ptr<const NL80211Packet>> response;
    290   if (!netlink_manager_->SendMessageAndGetAckOrError(trigger_scan,
    291                                                      error_code)) {
    292     // Logging is done inside |SendMessageAndGetAckOrError|.
    293     return false;
    294   }
    295   if (*error_code != 0) {
    296     LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN failed: " << strerror(*error_code);
    297     return false;
    298   }
    299   return true;
    300 }
    301 
    302 bool ScanUtils::StopScheduledScan(uint32_t interface_index) {
    303   NL80211Packet stop_sched_scan(
    304       netlink_manager_->GetFamilyId(),
    305       NL80211_CMD_STOP_SCHED_SCAN,
    306       netlink_manager_->GetSequenceNumber(),
    307       getpid());
    308   // Force an ACK response upon success.
    309   stop_sched_scan.AddFlag(NLM_F_ACK);
    310   stop_sched_scan.AddAttribute(
    311       NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index));
    312   vector<unique_ptr<const NL80211Packet>> response;
    313   int error_code;
    314   if (!netlink_manager_->SendMessageAndGetAckOrError(stop_sched_scan,
    315                                                      &error_code))  {
    316     LOG(ERROR) << "NL80211_CMD_STOP_SCHED_SCAN failed";
    317     return false;
    318   }
    319   if (error_code == ENOENT) {
    320     LOG(WARNING) << "Scheduled scan is not running!";
    321     return false;
    322   } else if (error_code != 0) {
    323     LOG(ERROR) << "Receive ERROR message in response to"
    324                << " 'stop scheduled scan' request: "
    325                << strerror(error_code);
    326     return false;
    327   }
    328   return true;
    329 }
    330 
    331 bool ScanUtils::AbortScan(uint32_t interface_index) {
    332   NL80211Packet abort_scan(
    333       netlink_manager_->GetFamilyId(),
    334       NL80211_CMD_ABORT_SCAN,
    335       netlink_manager_->GetSequenceNumber(),
    336       getpid());
    337 
    338   // Force an ACK response upon success.
    339   abort_scan.AddFlag(NLM_F_ACK);
    340   abort_scan.AddAttribute(
    341       NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index));
    342 
    343   if (!netlink_manager_->SendMessageAndGetAck(abort_scan)) {
    344     LOG(ERROR) << "NL80211_CMD_ABORT_SCAN failed";
    345     return false;
    346   }
    347   return true;
    348 }
    349 
    350 bool ScanUtils::StartScheduledScan(
    351     uint32_t interface_index,
    352     const SchedScanIntervalSetting& interval_setting,
    353     int32_t rssi_threshold,
    354     bool request_random_mac,
    355     const std::vector<std::vector<uint8_t>>& scan_ssids,
    356     const std::vector<std::vector<uint8_t>>& match_ssids,
    357     const std::vector<uint32_t>& freqs,
    358     int* error_code) {
    359   NL80211Packet start_sched_scan(
    360       netlink_manager_->GetFamilyId(),
    361       NL80211_CMD_START_SCHED_SCAN,
    362       netlink_manager_->GetSequenceNumber(),
    363       getpid());
    364   // Force an ACK response upon success.
    365   start_sched_scan.AddFlag(NLM_F_ACK);
    366 
    367   NL80211NestedAttr scan_ssids_attr(NL80211_ATTR_SCAN_SSIDS);
    368   for (size_t i = 0; i < scan_ssids.size(); i++) {
    369     scan_ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, scan_ssids[i]));
    370   }
    371   NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES);
    372   for (size_t i = 0; i < freqs.size(); i++) {
    373     freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i]));
    374   }
    375 
    376   //   Structure of attributes of scheduled scan filters:
    377   // |                                Nested Attribute: id: NL80211_ATTR_SCHED_SCAN_MATCH                           |
    378   // |     Nested Attributed: id: 0       |    Nested Attributed: id: 1         |      Nested Attr: id: 2     | ... |
    379   // | MATCH_SSID  | MATCH_RSSI(optional) | MATCH_SSID  | MACTCH_RSSI(optional) | MATCH_RSSI(optinal, global) | ... |
    380   NL80211NestedAttr scan_match_attr(NL80211_ATTR_SCHED_SCAN_MATCH);
    381   for (size_t i = 0; i < match_ssids.size(); i++) {
    382     NL80211NestedAttr match_group(i);
    383     match_group.AddAttribute(
    384         NL80211Attr<vector<uint8_t>>(NL80211_SCHED_SCAN_MATCH_ATTR_SSID, match_ssids[i]));
    385     match_group.AddAttribute(
    386         NL80211Attr<int32_t>(NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, rssi_threshold));
    387     scan_match_attr.AddAttribute(match_group);
    388   }
    389   start_sched_scan.AddAttribute(scan_match_attr);
    390 
    391   // Append all attributes to the NL80211_CMD_START_SCHED_SCAN packet.
    392   start_sched_scan.AddAttribute(
    393       NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index));
    394   start_sched_scan.AddAttribute(scan_ssids_attr);
    395   // An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to
    396   // scan all supported frequencies.
    397   if (!freqs.empty()) {
    398     start_sched_scan.AddAttribute(freqs_attr);
    399   }
    400 
    401   if (!interval_setting.plans.empty()) {
    402     NL80211NestedAttr scan_plans(NL80211_ATTR_SCHED_SCAN_PLANS);
    403     for (unsigned int i = 0; i < interval_setting.plans.size(); i++) {
    404       NL80211NestedAttr scan_plan(i + 1);
    405       scan_plan.AddAttribute(
    406           NL80211Attr<uint32_t>(NL80211_SCHED_SCAN_PLAN_INTERVAL,
    407                                 interval_setting.plans[i].interval_ms / kMsecPerSec));
    408       scan_plan.AddAttribute(
    409           NL80211Attr<uint32_t>(NL80211_SCHED_SCAN_PLAN_ITERATIONS,
    410                                 interval_setting.plans[i].n_iterations));
    411       scan_plans.AddAttribute(scan_plan);
    412     }
    413     NL80211NestedAttr last_scan_plan(interval_setting.plans.size() + 1);
    414     last_scan_plan.AddAttribute(
    415         NL80211Attr<uint32_t>(NL80211_SCHED_SCAN_PLAN_INTERVAL,
    416                               interval_setting.final_interval_ms / kMsecPerSec));
    417     scan_plans.AddAttribute(last_scan_plan);
    418     start_sched_scan.AddAttribute(scan_plans);
    419   } else {
    420     start_sched_scan.AddAttribute(
    421         NL80211Attr<uint32_t>(NL80211_ATTR_SCHED_SCAN_INTERVAL,
    422                               interval_setting.final_interval_ms));
    423   }
    424 
    425   if (request_random_mac) {
    426     start_sched_scan.AddAttribute(
    427         NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,
    428                               NL80211_SCAN_FLAG_RANDOM_ADDR));
    429   }
    430 
    431   vector<unique_ptr<const NL80211Packet>> response;
    432   if (!netlink_manager_->SendMessageAndGetAckOrError(start_sched_scan,
    433                                                      error_code)) {
    434     // Logging is done inside |SendMessageAndGetAckOrError|.
    435     return false;
    436   }
    437   if (*error_code != 0) {
    438     LOG(ERROR) << "NL80211_CMD_START_SCHED_SCAN failed: " << strerror(*error_code);
    439     return false;
    440   }
    441 
    442   return true;
    443 }
    444 
    445 }  // namespace wificond
    446 }  // namespace android
    447