Retrieve scan plan capabilities from kernel

Bug: 63837760
Test: compile, unit test
Test: manually inserting logs to test it retrieves the correct
values.

Change-Id: I750bd287b4f1cb8df44b8d1367c69f7963a3d8dc
diff --git a/client_interface_impl.cpp b/client_interface_impl.cpp
index 58edbbb..974ff17 100644
--- a/client_interface_impl.cpp
+++ b/client_interface_impl.cpp
@@ -164,6 +164,12 @@
       << static_cast<int>(scan_capabilities_.max_num_sched_scan_ssids) << endl;
   *ss << "Max number of match sets for scheduled scan: "
       << static_cast<int>(scan_capabilities_.max_match_sets) << endl;
+  *ss << "Maximum number of scan plans: "
+      << scan_capabilities_.max_num_scan_plans << endl;
+  *ss << "Max scan plan interval in seconds: "
+      << scan_capabilities_.max_scan_plan_interval << endl;
+  *ss << "Max scan plan iterations: "
+      << scan_capabilities_.max_scan_plan_iterations << endl;
   *ss << "Device supports random MAC for single shot scan: "
       << wiphy_features_.supports_random_mac_oneshot_scan << endl;
   *ss << "Device supports random MAC for scheduled scan: "
diff --git a/net/netlink_utils.cpp b/net/netlink_utils.cpp
index 0fa0116..18246f7 100644
--- a/net/netlink_utils.cpp
+++ b/net/netlink_utils.cpp
@@ -246,6 +246,17 @@
     return false;
   }
 
+  // Use default value 0 for scan plan capabilities if attributes are missing.
+  uint32_t max_num_scan_plans = 0;
+  packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
+                            &max_num_scan_plans);
+  uint32_t max_scan_plan_interval = 0;
+  packet->GetAttributeValue(NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
+                            &max_scan_plan_interval);
+  uint32_t max_scan_plan_iterations = 0;
+  packet->GetAttributeValue(NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
+                            &max_scan_plan_iterations);
+
   uint8_t max_match_sets;
   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_MATCH_SETS,
                                    &max_match_sets)) {
@@ -255,7 +266,10 @@
   }
   *out_scan_capabilities = ScanCapabilities(max_num_scan_ssids,
                                             max_num_sched_scan_ssids,
-                                            max_match_sets);
+                                            max_match_sets,
+                                            max_num_scan_plans,
+                                            max_scan_plan_interval,
+                                            max_scan_plan_iterations);
   return true;
 }
 
diff --git a/net/netlink_utils.h b/net/netlink_utils.h
index f8b9c0e..f1e43b5 100644
--- a/net/netlink_utils.h
+++ b/net/netlink_utils.h
@@ -65,16 +65,30 @@
   ScanCapabilities() = default;
   ScanCapabilities(uint8_t max_num_scan_ssids_,
                    uint8_t max_num_sched_scan_ssids_,
-                   uint8_t max_match_sets_)
+                   uint8_t max_match_sets_,
+                   uint32_t max_num_scan_plans_,
+                   uint32_t max_scan_plan_interval_,
+                   uint32_t max_scan_plan_iterations_)
       : max_num_scan_ssids(max_num_scan_ssids_),
         max_num_sched_scan_ssids(max_num_sched_scan_ssids_),
-        max_match_sets(max_match_sets_) {}
+        max_match_sets(max_match_sets_),
+        max_num_scan_plans(max_num_scan_plans_),
+        max_scan_plan_interval(max_scan_plan_interval_),
+        max_scan_plan_iterations(max_scan_plan_iterations_) {}
   // Number of SSIDs you can scan with a single scan request.
   uint8_t max_num_scan_ssids;
   // Number of SSIDs you can scan with a single scheduled scan request.
   uint8_t max_num_sched_scan_ssids;
   // Maximum number of sets that can be used with NL80211_ATTR_SCHED_SCAN_MATCH.
   uint8_t max_match_sets;
+  // Maximum number of scan plans that can be specified.
+  uint32_t max_num_scan_plans;
+  // Maximum interval in seconds for a particular scan plan that can be
+  // specified.
+  uint32_t max_scan_plan_interval;
+  // Maximum number of iterations for a particular scan plan that can be
+  // specified.
+  uint32_t max_scan_plan_iterations;
 };
 
 struct WiphyFeatures {
diff --git a/tests/netlink_utils_unittest.cpp b/tests/netlink_utils_unittest.cpp
index b1a7939..646d4a9 100644
--- a/tests/netlink_utils_unittest.cpp
+++ b/tests/netlink_utils_unittest.cpp
@@ -42,6 +42,9 @@
 constexpr uint8_t kFakeMaxNumScanSSIDs = 10;
 constexpr uint8_t kFakeMaxNumSchedScanSSIDs = 16;
 constexpr uint8_t kFakeMaxMatchSets = 18;
+constexpr uint8_t kFakeMaxNumScanPlans = 8;
+constexpr uint8_t kFakeMaxScanPlanIntervals = 80;
+constexpr uint8_t kFakeMaxScanPlanIterations = 10;
 constexpr uint16_t kFakeFamilyId = 14;
 constexpr uint32_t kFakeFrequency1 = 2412;
 constexpr uint32_t kFakeFrequency2 = 2437;
@@ -80,6 +83,116 @@
   return CreateControlMessageError(0);
 }
 
+void AppendScanCapabilitiesAttributes(NL80211Packet* packet,
+                                      bool supports_scan_plan) {
+  packet->AddAttribute(NL80211Attr<uint8_t>(NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+                                            kFakeMaxNumScanSSIDs));
+  packet->AddAttribute(NL80211Attr<uint8_t>(
+      NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+      kFakeMaxNumSchedScanSSIDs));
+  packet->AddAttribute(NL80211Attr<uint8_t>(NL80211_ATTR_MAX_MATCH_SETS,
+                                            kFakeMaxMatchSets));
+  if (supports_scan_plan) {
+    packet->AddAttribute(NL80211Attr<uint32_t>(
+        NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
+        kFakeMaxNumScanPlans));
+    packet->AddAttribute(NL80211Attr<uint32_t>(
+        NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
+        kFakeMaxScanPlanIntervals));
+    packet->AddAttribute(NL80211Attr<uint32_t>(
+        NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
+        kFakeMaxScanPlanIterations));
+  }
+}
+
+void AppendBandInfoAttributes(NL80211Packet* packet) {
+  NL80211NestedAttr freq_2g_1(1);
+  NL80211NestedAttr freq_2g_2(2);
+  NL80211NestedAttr freq_2g_3(3);
+  NL80211NestedAttr freq_5g_1(4);
+  NL80211NestedAttr freq_5g_2(5);
+  NL80211NestedAttr freq_dfs_1(6);
+  freq_2g_1.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
+                                               kFakeFrequency1));
+  freq_2g_2.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
+                                               kFakeFrequency2));
+  freq_2g_3.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
+                                               kFakeFrequency3));
+  freq_5g_1.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
+                                               kFakeFrequency4));
+  freq_5g_2.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
+                                               kFakeFrequency5));
+  // DFS frequency.
+  freq_dfs_1.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
+                                                kFakeFrequency6));
+  freq_dfs_1.AddAttribute(NL80211Attr<uint32_t>(
+      NL80211_FREQUENCY_ATTR_DFS_STATE,
+      NL80211_DFS_USABLE));
+
+  NL80211NestedAttr band_2g_freqs(NL80211_BAND_ATTR_FREQS);
+  NL80211NestedAttr band_5g_freqs(NL80211_BAND_ATTR_FREQS);
+  band_2g_freqs.AddAttribute(freq_2g_1);
+  band_2g_freqs.AddAttribute(freq_2g_2);
+  band_2g_freqs.AddAttribute(freq_2g_3);
+  band_5g_freqs.AddAttribute(freq_5g_1);
+  band_5g_freqs.AddAttribute(freq_5g_2);
+  band_5g_freqs.AddAttribute(freq_dfs_1);
+
+  NL80211NestedAttr band_2g_attr(1);
+  NL80211NestedAttr band_5g_attr(2);
+  band_2g_attr.AddAttribute(band_2g_freqs);
+  band_5g_attr.AddAttribute(band_5g_freqs);
+
+  NL80211NestedAttr band_attr(NL80211_ATTR_WIPHY_BANDS);
+  band_attr.AddAttribute(band_2g_attr);
+  band_attr.AddAttribute(band_5g_attr);
+
+  packet->AddAttribute(band_attr);
+}
+
+void AppendWiphyFeaturesAttributes(NL80211Packet* packet) {
+  packet->AddAttribute(NL80211Attr<uint32_t>(
+      NL80211_ATTR_FEATURE_FLAGS,
+      NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR));
+}
+
+void VerifyScanCapabilities(const ScanCapabilities& scan_capabilities,
+                            bool supports_scan_plan) {
+  EXPECT_EQ(scan_capabilities.max_num_scan_ssids,
+            kFakeMaxNumScanSSIDs);
+  EXPECT_EQ(scan_capabilities.max_num_sched_scan_ssids,
+            kFakeMaxNumSchedScanSSIDs);
+  EXPECT_EQ(scan_capabilities.max_match_sets,
+            kFakeMaxMatchSets);
+  if (supports_scan_plan) {
+    EXPECT_EQ(scan_capabilities.max_num_scan_plans,
+              kFakeMaxNumScanPlans);
+    EXPECT_EQ(scan_capabilities.max_scan_plan_interval,
+              kFakeMaxScanPlanIntervals);
+    EXPECT_EQ(scan_capabilities.max_scan_plan_iterations,
+              kFakeMaxScanPlanIterations);
+  } else {
+    EXPECT_EQ(scan_capabilities.max_num_scan_plans, (unsigned int) 0);
+    EXPECT_EQ(scan_capabilities.max_scan_plan_interval, (unsigned int) 0);
+    EXPECT_EQ(scan_capabilities.max_scan_plan_iterations, (unsigned int) 0);
+  }
+}
+
+void VerifyBandInfo(const BandInfo& band_info) {
+  vector<uint32_t> band_2g_expected = {kFakeFrequency1,
+      kFakeFrequency2, kFakeFrequency3};
+  vector<uint32_t> band_5g_expected = {kFakeFrequency4, kFakeFrequency5};
+  vector<uint32_t> band_dfs_expected = {kFakeFrequency6};
+  EXPECT_EQ(band_info.band_2g, band_2g_expected);
+  EXPECT_EQ(band_info.band_5g, band_5g_expected);
+  EXPECT_EQ(band_info.band_dfs, band_dfs_expected);
+}
+
+void VerifyWiphyFeatures(const WiphyFeatures& wiphy_features) {
+  EXPECT_TRUE(wiphy_features.supports_random_mac_oneshot_scan);
+  EXPECT_FALSE(wiphy_features.supports_random_mac_sched_scan);
+}
+
 }  // namespace
 
 class NetlinkUtilsTest : public ::testing::Test {
@@ -314,64 +427,9 @@
   new_wiphy.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY,
                                                kFakeWiphyIndex));
 
-  // Insert band information to mock netlink response.
-
-  NL80211NestedAttr freq_2g_1(1);
-  NL80211NestedAttr freq_2g_2(2);
-  NL80211NestedAttr freq_2g_3(3);
-  NL80211NestedAttr freq_5g_1(4);
-  NL80211NestedAttr freq_5g_2(5);
-  NL80211NestedAttr freq_dfs_1(6);
-  freq_2g_1.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
-                                               kFakeFrequency1));
-  freq_2g_2.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
-                                               kFakeFrequency2));
-  freq_2g_3.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
-                                               kFakeFrequency3));
-  freq_5g_1.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
-                                               kFakeFrequency4));
-  freq_5g_2.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
-                                               kFakeFrequency5));
-  // DFS frequency.
-  freq_dfs_1.AddAttribute(NL80211Attr<uint32_t>(NL80211_FREQUENCY_ATTR_FREQ,
-                                                kFakeFrequency6));
-  freq_dfs_1.AddAttribute(NL80211Attr<uint32_t>(
-      NL80211_FREQUENCY_ATTR_DFS_STATE,
-      NL80211_DFS_USABLE));
-
-  NL80211NestedAttr band_2g_freqs(NL80211_BAND_ATTR_FREQS);
-  NL80211NestedAttr band_5g_freqs(NL80211_BAND_ATTR_FREQS);
-  band_2g_freqs.AddAttribute(freq_2g_1);
-  band_2g_freqs.AddAttribute(freq_2g_2);
-  band_2g_freqs.AddAttribute(freq_2g_3);
-  band_5g_freqs.AddAttribute(freq_5g_1);
-  band_5g_freqs.AddAttribute(freq_5g_2);
-  band_5g_freqs.AddAttribute(freq_dfs_1);
-
-  NL80211NestedAttr band_2g_attr(1);
-  NL80211NestedAttr band_5g_attr(2);
-  band_2g_attr.AddAttribute(band_2g_freqs);
-  band_5g_attr.AddAttribute(band_5g_freqs);
-
-  NL80211NestedAttr band_attr(NL80211_ATTR_WIPHY_BANDS);
-  band_attr.AddAttribute(band_2g_attr);
-  band_attr.AddAttribute(band_5g_attr);
-
-  new_wiphy.AddAttribute(band_attr);
-
-  // Insert scan capabilities to mock netlink response.
-  new_wiphy.AddAttribute(NL80211Attr<uint8_t>(NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
-                                              kFakeMaxNumScanSSIDs));
-  new_wiphy.AddAttribute(NL80211Attr<uint8_t>(
-      NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
-      kFakeMaxNumSchedScanSSIDs));
-  new_wiphy.AddAttribute(NL80211Attr<uint8_t>(NL80211_ATTR_MAX_MATCH_SETS,
-                                              kFakeMaxMatchSets));
-
-  // Insert wiphy features to mock netlink response.
-  new_wiphy.AddAttribute(NL80211Attr<uint32_t>(
-      NL80211_ATTR_FEATURE_FLAGS,
-      NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR));
+  AppendBandInfoAttributes(&new_wiphy);
+  AppendScanCapabilitiesAttributes(&new_wiphy, true);
+  AppendWiphyFeaturesAttributes(&new_wiphy);
 
   vector<NL80211Packet> response = {new_wiphy};
 
@@ -385,29 +443,42 @@
                                            &band_info,
                                            &scan_capabilities,
                                            &wiphy_features));
-
-  // Verify band information.
-  vector<uint32_t> band_2g_expected = {kFakeFrequency1,
-      kFakeFrequency2, kFakeFrequency3};
-  vector<uint32_t> band_5g_expected = {kFakeFrequency4, kFakeFrequency5};
-  vector<uint32_t> band_dfs_expected = {kFakeFrequency6};
-  EXPECT_EQ(band_info.band_2g, band_2g_expected);
-  EXPECT_EQ(band_info.band_5g, band_5g_expected);
-  EXPECT_EQ(band_info.band_dfs, band_dfs_expected);
-
-  // Verify scan capabilities.
-  EXPECT_EQ(scan_capabilities.max_num_scan_ssids,
-            kFakeMaxNumScanSSIDs);
-  EXPECT_EQ(scan_capabilities.max_num_sched_scan_ssids,
-            kFakeMaxNumSchedScanSSIDs);
-  EXPECT_EQ(scan_capabilities.max_match_sets,
-            kFakeMaxMatchSets);
-
-  // Verify wiphy features.
-  EXPECT_TRUE(wiphy_features.supports_random_mac_oneshot_scan);
-  EXPECT_FALSE(wiphy_features.supports_random_mac_sched_scan);
+  VerifyBandInfo(band_info);
+  VerifyScanCapabilities(scan_capabilities, true);
+  VerifyWiphyFeatures(wiphy_features);
 }
 
+TEST_F(NetlinkUtilsTest, CanGetWiphyInfoScanPlanNotSupported) {
+  NL80211Packet new_wiphy(
+      netlink_manager_->GetFamilyId(),
+      NL80211_CMD_NEW_WIPHY,
+      netlink_manager_->GetSequenceNumber(),
+      getpid());
+  new_wiphy.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY,
+                                               kFakeWiphyIndex));
+
+  AppendBandInfoAttributes(&new_wiphy);
+  AppendScanCapabilitiesAttributes(&new_wiphy, false);
+  AppendWiphyFeaturesAttributes(&new_wiphy);
+
+  vector<NL80211Packet> response = {new_wiphy};
+
+  EXPECT_CALL(*netlink_manager_, SendMessageAndGetResponses(_, _)).
+      WillOnce(DoAll(MakeupResponse(response), Return(true)));
+
+  BandInfo band_info;
+  ScanCapabilities scan_capabilities;
+  WiphyFeatures wiphy_features;
+  EXPECT_TRUE(netlink_utils_->GetWiphyInfo(kFakeWiphyIndex,
+                                           &band_info,
+                                           &scan_capabilities,
+                                           &wiphy_features));
+  VerifyBandInfo(band_info);
+  VerifyScanCapabilities(scan_capabilities, false);
+  VerifyWiphyFeatures(wiphy_features);
+}
+
+
 TEST_F(NetlinkUtilsTest, CanHandleGetWiphyInfoError) {
   // Mock an error response from kernel.
   vector<NL80211Packet> response = {CreateControlMessageError(kFakeErrorCode)};