15a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang/* 25a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * Copyright (C) 2016 The Android Open Source Project 35a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * 45a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * Licensed under the Apache License, Version 2.0 (the "License"); 55a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * you may not use this file except in compliance with the License. 65a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * You may obtain a copy of the License at 75a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * 85a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * http://www.apache.org/licenses/LICENSE-2.0 95a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * 105a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * Unless required by applicable law or agreed to in writing, software 115a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * distributed under the License is distributed on an "AS IS" BASIS, 125a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * See the License for the specific language governing permissions and 145a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang * limitations under the License. 155a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang */ 165a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 175a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang#ifndef WIFICOND_SCANNING_SCAN_UTILS_H_ 185a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang#define WIFICOND_SCANNING_SCAN_UTILS_H_ 195a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 2021ff4c7ad0b0ec8da8392c00eedbae022d6e21e5Ningyuan Wang#include <memory> 215a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang#include <vector> 225a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 235a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang#include <android-base/macros.h> 245a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 2514de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang#include "wificond/net/netlink_manager.h" 2614de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang 274d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wangnamespace com { 284d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wangnamespace android { 294d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wangnamespace server { 304d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wangnamespace wifi { 314d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wangnamespace wificond { 324d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang 334d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wangclass NativeScanResult; 340482e6d44600d35f159d9705050277196d6aa59cRoshan Piusclass RadioChainInfo; 354d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang 364d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang} // namespace wificond 374d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang} // namespace wifi 384d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang} // namespace server 394d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang} // namespace android 404d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang} // namespace com 414d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang 425a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wangnamespace android { 435a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wangnamespace wificond { 445a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 451aadd2c3781ee882e77dae2f4dc38fe3574fdca7Ningyuan Wangclass NL80211NestedAttr; 465a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wangclass NL80211Packet; 475a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 48dfbe7e4e12824527fac840391f31d2b4a4578e3eNingyuan Wangstruct SchedScanIntervalSetting { 49dfbe7e4e12824527fac840391f31d2b4a4578e3eNingyuan Wang struct ScanPlan { 50dfbe7e4e12824527fac840391f31d2b4a4578e3eNingyuan Wang uint32_t interval_ms; 51dfbe7e4e12824527fac840391f31d2b4a4578e3eNingyuan Wang uint32_t n_iterations; 52dfbe7e4e12824527fac840391f31d2b4a4578e3eNingyuan Wang }; 53dfbe7e4e12824527fac840391f31d2b4a4578e3eNingyuan Wang std::vector<ScanPlan> plans; 54dfbe7e4e12824527fac840391f31d2b4a4578e3eNingyuan Wang // After |plans| has been exhausted, scan at every 55dfbe7e4e12824527fac840391f31d2b4a4578e3eNingyuan Wang // |final_interval_ms|. 56dfbe7e4e12824527fac840391f31d2b4a4578e3eNingyuan Wang uint32_t final_interval_ms{0}; 57dfbe7e4e12824527fac840391f31d2b4a4578e3eNingyuan Wang}; 58dfbe7e4e12824527fac840391f31d2b4a4578e3eNingyuan Wang 595a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang// Provides scanning helper functions. 605a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wangclass ScanUtils { 615a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang public: 625a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang explicit ScanUtils(NetlinkManager* netlink_manager); 635a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang virtual ~ScanUtils(); 645a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 655a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang // Send 'get scan results' request to kernel and get the latest scan results. 665a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang // |interface_index| is the index of interface we want to get scan results 675a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang // from. 685a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang // A vector of ScanResult object will be returned by |*out_scan_results|. 695a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang // Returns true on success. 704d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang virtual bool GetScanResult( 714d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang uint32_t interface_index, 724d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang std::vector<::com::android::server::wifi::wificond::NativeScanResult>* out_scan_results); 735a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 745a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang // Send scan request to kernel for interface with index |interface_index|. 759d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |request_random_mac| If true, request device/driver to use a random MAC 769d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // address during scan. Requires |supports_random_mac_sched_scan| 7713b4064f889935091b0d55bbb056ec143972a9a4Ningyuan Wang // address during scan. 789d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |scan_type| Type of scan to perform. One of, 799d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // |SCAN_TYPE_LOW_SPAN| (prioritize to reduce latency over other scan 809d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // performance attributes), 819d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // |SCAN_TYPE_LOW_POWER| (prioritize to reduce power consumption over other 829d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // scan performance attributes), 839d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // |SCAN_TYPE_HIGH_ACCURACY| (prioritize to increase accuracy over other scan 849d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // performance atrributes) OR 859d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // |SCAN_TYPE_DEFAULT| (no prioritization). 869d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |ssids| is a vector of ssids we request to scan, which mostly is used 875a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang // for hidden networks. 885a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang // If |ssids| is an empty vector, it will do a passive scan. 895a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang // If |ssids| contains an empty string, it will a scan for all ssids. 909d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |freqs| is a vector of frequencies we request to scan. 915a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang // If |freqs| is an empty vector, it will scan all supported frequencies. 929d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |error_code| contains the errno kernel replied when this returns false. 935a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang // Returns true on success. 945a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang virtual bool Scan(uint32_t interface_index, 9513b4064f889935091b0d55bbb056ec143972a9a4Ningyuan Wang bool request_random_mac, 969d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius int scan_type, 975a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang const std::vector<std::vector<uint8_t>>& ssids, 98793978cb7f2f227f1ab28135caeb75dd4ed48e6cNingyuan Wang const std::vector<uint32_t>& freqs, 99793978cb7f2f227f1ab28135caeb75dd4ed48e6cNingyuan Wang int* error_code); 1005a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 101ebe363ff1e912429c1691a00a29bf6bc83e5c08aNingyuan Wang // Send scan request to kernel for interface with index |interface_index|. 1029d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |inteval_ms| is the expected scan interval in milliseconds. 1039d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |rssi_threshold_2g| is the minimum RSSI threshold value as a filter for 104c6ecdf8ea59f7de47edfd6161f059b8ab45d1f8fNingyuan Wang // 2GHz band. 1059d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |rssi_threshold_5g| is the minimum RSSI threshold value as a filter for 106c6ecdf8ea59f7de47edfd6161f059b8ab45d1f8fNingyuan Wang // 5GHz band. 1079d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |scan_ssids| is a vector of ssids we request to scan, which is mostly 108ebe363ff1e912429c1691a00a29bf6bc83e5c08aNingyuan Wang // used for hidden networks. 1099d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |request_random_mac| If true, request device/driver to use a random MAC 1109d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // address during scan. Requires |supports_random_mac_sched_scan| 1119d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |request_low_power|: If true, prioritize power consumption over 1129d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // other scan performance attributes. 1139d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // Requires |supports_low_power_oneshot_scan|. 1149d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |scan_ssids| is the list of ssids to actively scan for. 115ebe363ff1e912429c1691a00a29bf6bc83e5c08aNingyuan Wang // If |scan_ssids| is an empty vector, it will do a passive scan. 116ebe363ff1e912429c1691a00a29bf6bc83e5c08aNingyuan Wang // If |scan_ssids| contains an empty string, it will a scan for all ssids. 1179d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |match_ssids| is the list of ssids that we want to add as filters. 1189d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |freqs| is a vector of frequencies we request to scan. 119ebe363ff1e912429c1691a00a29bf6bc83e5c08aNingyuan Wang // If |freqs| is an empty vector, it will scan all supported frequencies. 1209d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius // - |error_code| contains the errno kernel replied when this returns false. 121ebe363ff1e912429c1691a00a29bf6bc83e5c08aNingyuan Wang // Only BSSs match the |match_ssids| and |rssi_threshold| will be returned as 122ebe363ff1e912429c1691a00a29bf6bc83e5c08aNingyuan Wang // scan results. 123ebe363ff1e912429c1691a00a29bf6bc83e5c08aNingyuan Wang // Returns true on success. 12465b365fe4b6a99f9dab98515c1b96bd725cb56a8Ningyuan Wang virtual bool StartScheduledScan( 125ebe363ff1e912429c1691a00a29bf6bc83e5c08aNingyuan Wang uint32_t interface_index, 126dfbe7e4e12824527fac840391f31d2b4a4578e3eNingyuan Wang const SchedScanIntervalSetting& interval_setting, 127c6ecdf8ea59f7de47edfd6161f059b8ab45d1f8fNingyuan Wang int32_t rssi_threshold_2g, 128c6ecdf8ea59f7de47edfd6161f059b8ab45d1f8fNingyuan Wang int32_t rssi_threshold_5g, 12913b4064f889935091b0d55bbb056ec143972a9a4Ningyuan Wang bool request_random_mac, 1309d096b2f0027b91e5eed40c0e2482d238cdf7c8aRoshan Pius bool request_low_power, 131ebe363ff1e912429c1691a00a29bf6bc83e5c08aNingyuan Wang const std::vector<std::vector<uint8_t>>& scan_ssids, 132ebe363ff1e912429c1691a00a29bf6bc83e5c08aNingyuan Wang const std::vector<std::vector<uint8_t>>& match_ssids, 133793978cb7f2f227f1ab28135caeb75dd4ed48e6cNingyuan Wang const std::vector<uint32_t>& freqs, 134793978cb7f2f227f1ab28135caeb75dd4ed48e6cNingyuan Wang int* error_code); 135ebe363ff1e912429c1691a00a29bf6bc83e5c08aNingyuan Wang 1368044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang // Stop existing scheduled scan on interface with index |interface_index|. 1378044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang // Returns true on success. 1388044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang // Returns false on error or when there is no scheduled scan running. 1398044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang virtual bool StopScheduledScan(uint32_t interface_index); 1408044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang 14133bbb8147436c2abf8f3e7b535b13b6c63bd3c64Daisuke Niwa // Abort ongoing single scan on interface with index |interface_index|. 14233bbb8147436c2abf8f3e7b535b13b6c63bd3c64Daisuke Niwa // Returns true on success. 14333bbb8147436c2abf8f3e7b535b13b6c63bd3c64Daisuke Niwa virtual bool AbortScan(uint32_t interface_index); 14433bbb8147436c2abf8f3e7b535b13b6c63bd3c64Daisuke Niwa 1451aadd2c3781ee882e77dae2f4dc38fe3574fdca7Ningyuan Wang // Visible for testing. 1461aadd2c3781ee882e77dae2f4dc38fe3574fdca7Ningyuan Wang // Get a timestamp for the scan result |bss| represents. 1471aadd2c3781ee882e77dae2f4dc38fe3574fdca7Ningyuan Wang // This timestamp records the time passed since boot when last time the 1481aadd2c3781ee882e77dae2f4dc38fe3574fdca7Ningyuan Wang // AP was seen. 1491aadd2c3781ee882e77dae2f4dc38fe3574fdca7Ningyuan Wang virtual bool GetBssTimestampForTesting( 1501aadd2c3781ee882e77dae2f4dc38fe3574fdca7Ningyuan Wang const NL80211NestedAttr& bss, 1511aadd2c3781ee882e77dae2f4dc38fe3574fdca7Ningyuan Wang uint64_t* last_seen_since_boot_microseconds); 1521aadd2c3781ee882e77dae2f4dc38fe3574fdca7Ningyuan Wang 15314de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang // Sign up to be notified when new scan results are available. 15414de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang // |handler| will be called when the kernel signals to wificond that a scan 15514de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang // has been completed on the given |interface_index|. See the declaration of 15614de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang // OnScanResultsReadyHandler for documentation on the semantics of this 15714de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang // callback. 15814de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang virtual void SubscribeScanResultNotification( 15914de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang uint32_t interface_index, 16014de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang OnScanResultsReadyHandler handler); 16114de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang 16214de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang // Cancel the sign-up of receiving new scan result notification from 16314de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang // interface with index |interface_index|. 16414de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang virtual void UnsubscribeScanResultNotification(uint32_t interface_index); 16514de8b2ce5ef49218e48002a3ac0728847e90372Ningyuan Wang 1668044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang // Sign up to be notified when new scan results are available. 1678044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang // |handler| will be called when the kernel signals to wificond that a 1688044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang // scheduled scan has been completed on the given |interface_index|. 1698044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang // See the declaration of OnSchedScanResultsReadyHandler for documentation 1708044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang // on the semantics of this callback. 1718044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang virtual void SubscribeSchedScanResultNotification( 1728044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang uint32_t interface_index, 1738044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang OnSchedScanResultsReadyHandler handler); 1748044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang 1758044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang // Cancel the sign-up of receiving new scheduled scan result notification from 1768044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang // interface with index |interface_index|. 1778044a946f4b350291ddd44c52db7ca34e21bad8fNingyuan Wang virtual void UnsubscribeSchedScanResultNotification(uint32_t interface_index); 178a5cc66dc98eeb29138164f497bb0e39352df5f36Ningyuan Wang 1795a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang private: 1801aadd2c3781ee882e77dae2f4dc38fe3574fdca7Ningyuan Wang bool GetBssTimestamp(const NL80211NestedAttr& bss, 1811aadd2c3781ee882e77dae2f4dc38fe3574fdca7Ningyuan Wang uint64_t* last_seen_since_boot_microseconds); 1820482e6d44600d35f159d9705050277196d6aa59cRoshan Pius bool ParseRadioChainInfos( 1830482e6d44600d35f159d9705050277196d6aa59cRoshan Pius const NL80211NestedAttr& bss, 1840482e6d44600d35f159d9705050277196d6aa59cRoshan Pius std::vector<::com::android::server::wifi::wificond::RadioChainInfo> 1850482e6d44600d35f159d9705050277196d6aa59cRoshan Pius *radio_chain_infos); 1865a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang bool GetSSIDFromInfoElement(const std::vector<uint8_t>& ie, 1875a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang std::vector<uint8_t>* ssid); 1885a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang // Converts a NL80211_CMD_NEW_SCAN_RESULTS packet to a ScanResult object. 1894d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang bool ParseScanResult( 1904d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang std::unique_ptr<const NL80211Packet> packet, 1914d882abea2a9956689d32820a5c13e9f9625e0daNingyuan Wang ::com::android::server::wifi::wificond::NativeScanResult* scan_result); 1925a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 1935a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang NetlinkManager* netlink_manager_; 1945a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 1955a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang DISALLOW_COPY_AND_ASSIGN(ScanUtils); 1965a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang}; 1975a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 1985a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang} // namespace wificond 1995a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang} // namespace android 2005a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang 2015a34c89bf63f387c38b5e60e8c733de7051e22aeNingyuan Wang#endif // WIFICOND_SCANNING_SCAN_UTILS_H_ 202