438 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			438 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * Copyright (C) 2016, The Android Open Source Project
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| #include <array>
 | |
| #include <memory>
 | |
| 
 | |
| #include <gmock/gmock.h>
 | |
| #include <gtest/gtest.h>
 | |
| #include <wifi_system_test/mock_interface_tool.h>
 | |
| 
 | |
| #include "android/net/wifi/nl80211/IApInterface.h"
 | |
| #include "wificond/tests/mock_netlink_manager.h"
 | |
| #include "wificond/tests/mock_netlink_utils.h"
 | |
| #include "wificond/tests/mock_scan_utils.h"
 | |
| #include "wificond/server.h"
 | |
| 
 | |
| using android::net::wifi::nl80211::IApInterface;
 | |
| using android::net::wifi::nl80211::IClientInterface;
 | |
| using android::wifi_system::InterfaceTool;
 | |
| using android::wifi_system::MockInterfaceTool;
 | |
| using std::unique_ptr;
 | |
| using std::vector;
 | |
| using testing::Eq;
 | |
| using testing::Invoke;
 | |
| using testing::NiceMock;
 | |
| using testing::Return;
 | |
| using testing::Sequence;
 | |
| using testing::StrEq;
 | |
| using testing::_;
 | |
| 
 | |
| using namespace std::placeholders;
 | |
| 
 | |
| namespace android {
 | |
| namespace wificond {
 | |
| namespace {
 | |
| 
 | |
| const char kFakeInterfaceName[] = "testif0";
 | |
| const char kFakeInterfaceName1[] = "testif1";
 | |
| const char kFakeInterfaceNameP2p[] = "testif-p2p0";
 | |
| const char kFateInterfaceNameInvalid[] = "testif-invalid";
 | |
| const uint32_t kFakeInterfaceIndex = 34;
 | |
| const uint32_t kFakeInterfaceIndex1 = 36;
 | |
| const uint32_t kFakeInterfaceIndexP2p = 36;
 | |
| const uint32_t kFakeWiphyIndex = 0;
 | |
| const std::array<uint8_t, ETH_ALEN> kFakeInterfaceMacAddress = {0x45, 0x54, 0xad, 0x67, 0x98, 0xf6};
 | |
| const std::array<uint8_t, ETH_ALEN> kFakeInterfaceMacAddress1 = {0x05, 0x04, 0xef, 0x27, 0x12, 0xff};
 | |
| const std::array<uint8_t, ETH_ALEN> kFakeInterfaceMacAddressP2p = {0x15, 0x24, 0xef, 0x27, 0x12, 0xff};
 | |
| 
 | |
| // This is a helper function to mock the behavior of
 | |
| // NetlinkUtils::GetInterfaces().
 | |
| // |wiphy_index| is mapped to first parameters of GetInterfaces().
 | |
| // |response| is mapped to second parameters of GetInterfaces().
 | |
| // |mock_response| and |mock_return_value| are additional parameters used
 | |
| // for specifying expected results,
 | |
| bool MockGetInterfacesResponse(
 | |
|     const vector<InterfaceInfo>& mock_response,
 | |
|     bool mock_return_value,
 | |
|     uint32_t wiphy_index,
 | |
|     vector<InterfaceInfo>* response) {
 | |
|   for (const auto& interface : mock_response) {
 | |
|     response->emplace_back(interface);
 | |
|   }
 | |
|   return mock_return_value;
 | |
| }
 | |
| 
 | |
| class ServerTest : public ::testing::Test {
 | |
|  protected:
 | |
|   void SetUp() override {
 | |
|     ON_CALL(*if_tool_, SetUpState(_, _)).WillByDefault(Return(true));
 | |
|     ON_CALL(*netlink_utils_, GetWiphyIndex(_)).WillByDefault(Return(true));
 | |
|     ON_CALL(*netlink_utils_, GetWiphyIndex(_, _)).WillByDefault(Return(true));
 | |
|     ON_CALL(*netlink_utils_, GetInterfaces(_, _))
 | |
|       .WillByDefault(Invoke(bind(
 | |
|           MockGetInterfacesResponse, mock_interfaces, true, _1, _2)));
 | |
|     ON_CALL(*netlink_utils_, GetWiphyInfo(0, _, _, _))
 | |
|           .WillByDefault([](
 | |
|               uint32_t wiphy_index,
 | |
|               BandInfo* band_info,
 | |
|               ScanCapabilities* scan_capabilities,
 | |
|               WiphyFeatures* wiphy_features) {
 | |
|             band_info->band_2g = {1, 2, 3, 4, 5};
 | |
|             return true;
 | |
|           });
 | |
|     ON_CALL(*netlink_utils_, GetWiphyInfo(1, _, _, _))
 | |
|           .WillByDefault([](
 | |
|               uint32_t wiphy_index,
 | |
|               BandInfo* band_info,
 | |
|               ScanCapabilities* scan_capabilities,
 | |
|               WiphyFeatures* wiphy_features) {
 | |
|             band_info->band_60g = {6, 7, 8, 9, 10};
 | |
|             return true;
 | |
|           });
 | |
|   }
 | |
| 
 | |
|   NiceMock<MockInterfaceTool>* if_tool_ = new NiceMock<MockInterfaceTool>;
 | |
| 
 | |
|   unique_ptr<NiceMock<MockNetlinkManager>> netlink_manager_{
 | |
|       new NiceMock<MockNetlinkManager>()};
 | |
| 
 | |
|   unique_ptr<NiceMock<MockNetlinkUtils>> netlink_utils_{
 | |
|       new NiceMock<MockNetlinkUtils>(netlink_manager_.get())};
 | |
|   unique_ptr<NiceMock<MockScanUtils>> scan_utils_{
 | |
|       new NiceMock<MockScanUtils>(netlink_manager_.get())};
 | |
|   const vector<InterfaceInfo> mock_interfaces = {
 | |
|       // Client interface
 | |
|       InterfaceInfo(
 | |
|           kFakeInterfaceIndex,
 | |
|           kFakeWiphyIndex,
 | |
|           std::string(kFakeInterfaceName),
 | |
|           std::array<uint8_t, ETH_ALEN>(kFakeInterfaceMacAddress)),
 | |
|       // AP Interface
 | |
|       InterfaceInfo(
 | |
|           kFakeInterfaceIndex1,
 | |
|           kFakeWiphyIndex,
 | |
|           std::string(kFakeInterfaceName1),
 | |
|           std::array<uint8_t, ETH_ALEN>(kFakeInterfaceMacAddress1)),
 | |
|       // p2p interface
 | |
|       InterfaceInfo(
 | |
|           kFakeInterfaceIndexP2p,
 | |
|           kFakeWiphyIndex,
 | |
|           std::string(kFakeInterfaceNameP2p),
 | |
|           std::array<uint8_t, ETH_ALEN>(kFakeInterfaceMacAddressP2p))
 | |
|   };
 | |
| 
 | |
|   Server server_{unique_ptr<InterfaceTool>(if_tool_),
 | |
|                  netlink_utils_.get(),
 | |
|                  scan_utils_.get()};
 | |
| };  // class ServerTest
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| TEST_F(ServerTest, CanSetUpApInterface) {
 | |
|   sp<IApInterface> ap_if;
 | |
|   EXPECT_CALL(*netlink_utils_, SubscribeRegDomainChange(_, _));
 | |
| 
 | |
|   EXPECT_TRUE(server_.createApInterface(kFakeInterfaceName, &ap_if).isOk());
 | |
|   EXPECT_NE(nullptr, ap_if.get());
 | |
| }
 | |
| 
 | |
| TEST_F(ServerTest, CanSupportMultipleInterfaces) {
 | |
|   sp<IApInterface> ap_if;
 | |
| 
 | |
|   EXPECT_TRUE(server_.createApInterface(kFakeInterfaceName, &ap_if).isOk());
 | |
|   EXPECT_NE(nullptr, ap_if.get());
 | |
| 
 | |
|   sp<IApInterface> second_ap_if;
 | |
|   // We won't throw on a second interface request.
 | |
|   EXPECT_TRUE(server_.createApInterface(kFakeInterfaceName, &second_ap_if).isOk());
 | |
|   // But this time we won't get an interface back.
 | |
|   EXPECT_NE(nullptr, second_ap_if.get());
 | |
| }
 | |
| 
 | |
| TEST_F(ServerTest, CanDestroyInterfaces) {
 | |
|   sp<IApInterface> ap_if;
 | |
| 
 | |
|   EXPECT_TRUE(server_.createApInterface(kFakeInterfaceName, &ap_if).isOk());
 | |
| 
 | |
|   // When we tear down the interface, we expect the driver to be unloaded.
 | |
|   EXPECT_CALL(*netlink_utils_, UnsubscribeRegDomainChange(_));
 | |
|   EXPECT_TRUE(server_.tearDownInterfaces().isOk());
 | |
|   // After a tearDown, we should be able to create another interface.
 | |
|   EXPECT_TRUE(server_.createApInterface(kFakeInterfaceName, &ap_if).isOk());
 | |
| }
 | |
| 
 | |
| TEST_F(ServerTest, CanTeardownApInterface) {
 | |
|   sp<IApInterface> ap_if;
 | |
| 
 | |
|   EXPECT_TRUE(server_.createApInterface(kFakeInterfaceName, &ap_if).isOk());
 | |
|   EXPECT_NE(nullptr, ap_if.get());
 | |
| 
 | |
|   // Try to remove an invalid iface name, this should fail.
 | |
|   bool success = true;
 | |
|   EXPECT_TRUE(server_.tearDownApInterface(
 | |
|       kFateInterfaceNameInvalid, &success).isOk());
 | |
|   EXPECT_FALSE(success);
 | |
| 
 | |
|   EXPECT_TRUE(server_.tearDownApInterface(kFakeInterfaceName, &success).isOk());
 | |
|   EXPECT_TRUE(success);
 | |
| }
 | |
| 
 | |
| TEST_F(ServerTest, CanTeardownClientInterface) {
 | |
|   sp<IClientInterface> client_if;
 | |
| 
 | |
|   EXPECT_TRUE(server_.createClientInterface(
 | |
|       kFakeInterfaceName, &client_if).isOk());
 | |
|   EXPECT_NE(nullptr, client_if.get());
 | |
| 
 | |
|   // Try to remove an invalid iface name, this should fail.
 | |
|   bool success = true;
 | |
|   EXPECT_TRUE(server_.tearDownClientInterface(
 | |
|       kFateInterfaceNameInvalid, &success).isOk());
 | |
|   EXPECT_FALSE(success);
 | |
| 
 | |
|   EXPECT_TRUE(server_.tearDownClientInterface(
 | |
|       kFakeInterfaceName, &success).isOk());
 | |
|   EXPECT_TRUE(success);
 | |
| }
 | |
| 
 | |
| TEST_F(ServerTest, CanTeardownMultipleClientInterfacesOnSameWiphy) {
 | |
|   sp<IClientInterface> client_if;
 | |
| 
 | |
|   // add iface 0 on wiphy 0
 | |
|   ON_CALL(*netlink_utils_, GetWiphyIndex(_, _)).WillByDefault(
 | |
|       [](uint32_t* out_wiphy_index, const std::string& iface_name) {
 | |
|         *out_wiphy_index = 0;
 | |
|         return true;
 | |
|       });
 | |
| 
 | |
|   EXPECT_TRUE(server_.createClientInterface(
 | |
|       kFakeInterfaceName, &client_if).isOk());
 | |
|   EXPECT_NE(nullptr, client_if.get());
 | |
| 
 | |
|   // bands non-empty
 | |
|   {
 | |
|      std::optional<std::vector<int32_t>> out_frequencies;
 | |
|      EXPECT_TRUE(server_.getAvailable2gChannels(&out_frequencies).isOk());
 | |
|      EXPECT_TRUE(out_frequencies.has_value());
 | |
|      EXPECT_FALSE(out_frequencies->empty());
 | |
|   }
 | |
| 
 | |
|   sp<IClientInterface> client_if1;
 | |
| 
 | |
|   // add iface 1 on wiphy 0
 | |
|   ON_CALL(*netlink_utils_, GetWiphyIndex(_, _)).WillByDefault(
 | |
|       [](uint32_t* out_wiphy_index, const std::string& iface_name) {
 | |
|         *out_wiphy_index = 0;
 | |
|         return true;
 | |
|       });
 | |
| 
 | |
|   EXPECT_TRUE(server_.createClientInterface(
 | |
|       kFakeInterfaceName1, &client_if1).isOk());
 | |
|   EXPECT_NE(nullptr, client_if1.get());
 | |
| 
 | |
|   // bands still non-empty
 | |
|   {
 | |
|      std::optional<std::vector<int32_t>> out_frequencies;
 | |
|      EXPECT_TRUE(server_.getAvailable2gChannels(&out_frequencies).isOk());
 | |
|      EXPECT_TRUE(out_frequencies.has_value());
 | |
|      EXPECT_FALSE(out_frequencies->empty());
 | |
|   }
 | |
| 
 | |
|   // tear down iface 0
 | |
|   {
 | |
|     bool success = true;
 | |
|     EXPECT_TRUE(server_.tearDownClientInterface(
 | |
|         kFakeInterfaceName, &success).isOk());
 | |
|     EXPECT_TRUE(success);
 | |
|   }
 | |
| 
 | |
|   // bands still non-empty
 | |
|   {
 | |
|     std::optional<std::vector<int32_t>> out_frequencies;
 | |
|     EXPECT_TRUE(server_.getAvailable2gChannels(&out_frequencies).isOk());
 | |
|     EXPECT_TRUE(out_frequencies.has_value());
 | |
|     EXPECT_FALSE(out_frequencies->empty());
 | |
|   }
 | |
| 
 | |
|   // tear down iface 1
 | |
|   {
 | |
|     bool success = true;
 | |
|     EXPECT_TRUE(server_.tearDownClientInterface(
 | |
|         kFakeInterfaceName1, &success).isOk());
 | |
|     EXPECT_TRUE(success);
 | |
|   }
 | |
| 
 | |
|   // bands now empty
 | |
|   {
 | |
|     std::optional<std::vector<int32_t>> out_frequencies;
 | |
|     EXPECT_TRUE(server_.getAvailable2gChannels(&out_frequencies).isOk());
 | |
|     EXPECT_FALSE(out_frequencies.has_value());
 | |
|   }
 | |
| }
 | |
| 
 | |
| TEST_F(ServerTest, CanTeardownMultipleClientInterfacesOnDifferentWiphy) {
 | |
|   sp<IClientInterface> client_if;
 | |
| 
 | |
|   // add iface 0 on wiphy 0, supports 2GHz
 | |
|   ON_CALL(*netlink_utils_, GetWiphyIndex(_, _)).WillByDefault(
 | |
|       [](uint32_t* out_wiphy_index, const std::string& iface_name) {
 | |
|         *out_wiphy_index = 0;
 | |
|         return true;
 | |
|       });
 | |
| 
 | |
|   EXPECT_TRUE(server_.createClientInterface(
 | |
|       kFakeInterfaceName, &client_if).isOk());
 | |
|   EXPECT_NE(nullptr, client_if.get());
 | |
| 
 | |
|   // 2G bands non-empty
 | |
|   {
 | |
|      std::optional<std::vector<int32_t>> out_frequencies;
 | |
|      EXPECT_TRUE(server_.getAvailable2gChannels(&out_frequencies).isOk());
 | |
|      EXPECT_TRUE(out_frequencies.has_value());
 | |
|      EXPECT_FALSE(out_frequencies->empty());
 | |
|   }
 | |
| 
 | |
|   // 60G bands empty
 | |
|   {
 | |
|      std::optional<std::vector<int32_t>> out_frequencies;
 | |
|      EXPECT_TRUE(server_.getAvailable60gChannels(&out_frequencies).isOk());
 | |
|      EXPECT_FALSE(out_frequencies.has_value());
 | |
|   }
 | |
| 
 | |
|   sp<IClientInterface> client_if1;
 | |
| 
 | |
|   // add iface 1 on wiphy 1, supports 60GHz
 | |
|   ON_CALL(*netlink_utils_, GetWiphyIndex(_, _)).WillByDefault(
 | |
|       [](uint32_t* out_wiphy_index, const std::string& iface_name) {
 | |
|         *out_wiphy_index = 1;
 | |
|         return true;
 | |
|       });
 | |
| 
 | |
|   EXPECT_TRUE(server_.createClientInterface(
 | |
|       kFakeInterfaceName1, &client_if1).isOk());
 | |
|   EXPECT_NE(nullptr, client_if1.get());
 | |
| 
 | |
|   // 2G bands still non-empty
 | |
|   {
 | |
|      std::optional<std::vector<int32_t>> out_frequencies;
 | |
|      EXPECT_TRUE(server_.getAvailable2gChannels(&out_frequencies).isOk());
 | |
|      EXPECT_TRUE(out_frequencies.has_value());
 | |
|      EXPECT_FALSE(out_frequencies->empty());
 | |
|   }
 | |
| 
 | |
|   // 60G bands non-empty
 | |
|   {
 | |
|      std::optional<std::vector<int32_t>> out_frequencies;
 | |
|      EXPECT_TRUE(server_.getAvailable60gChannels(&out_frequencies).isOk());
 | |
|      EXPECT_TRUE(out_frequencies.has_value());
 | |
|      EXPECT_FALSE(out_frequencies->empty());
 | |
|   }
 | |
| 
 | |
|   // tear down iface 0
 | |
|   {
 | |
|     bool success = true;
 | |
|     EXPECT_TRUE(server_.tearDownClientInterface(
 | |
|         kFakeInterfaceName, &success).isOk());
 | |
|     EXPECT_TRUE(success);
 | |
|   }
 | |
| 
 | |
|   // 2G bands now empty
 | |
|   {
 | |
|     std::optional<std::vector<int32_t>> out_frequencies;
 | |
|     EXPECT_TRUE(server_.getAvailable2gChannels(&out_frequencies).isOk());
 | |
|     EXPECT_FALSE(out_frequencies.has_value());
 | |
|   }
 | |
| 
 | |
|   // 60G bands still non-empty
 | |
|   {
 | |
|      std::optional<std::vector<int32_t>> out_frequencies;
 | |
|      EXPECT_TRUE(server_.getAvailable60gChannels(&out_frequencies).isOk());
 | |
|      EXPECT_TRUE(out_frequencies.has_value());
 | |
|      EXPECT_FALSE(out_frequencies->empty());
 | |
|   }
 | |
| 
 | |
|   // tear down iface 1
 | |
|   {
 | |
|     bool success = true;
 | |
|     EXPECT_TRUE(server_.tearDownClientInterface(
 | |
|         kFakeInterfaceName1, &success).isOk());
 | |
|     EXPECT_TRUE(success);
 | |
|   }
 | |
| 
 | |
|   // 2G bands still empty
 | |
|   {
 | |
|     std::optional<std::vector<int32_t>> out_frequencies;
 | |
|     EXPECT_TRUE(server_.getAvailable2gChannels(&out_frequencies).isOk());
 | |
|     EXPECT_FALSE(out_frequencies.has_value());
 | |
|   }
 | |
| 
 | |
|   // 60G bands now empty
 | |
|   {
 | |
|      std::optional<std::vector<int32_t>> out_frequencies;
 | |
|      EXPECT_TRUE(server_.getAvailable60gChannels(&out_frequencies).isOk());
 | |
|      EXPECT_FALSE(out_frequencies.has_value());
 | |
|   }
 | |
| }
 | |
| 
 | |
| TEST_F(ServerTest, CanCreateTeardownApAndClientInterface) {
 | |
|   sp<IClientInterface> client_if;
 | |
|   sp<IApInterface> ap_if;
 | |
| 
 | |
|   EXPECT_TRUE(server_.createClientInterface(kFakeInterfaceName, &client_if).isOk());
 | |
|   EXPECT_NE(nullptr, client_if.get());
 | |
| 
 | |
|   EXPECT_TRUE(server_.createApInterface(kFakeInterfaceName1, &ap_if).isOk());
 | |
|   EXPECT_NE(nullptr, ap_if.get());
 | |
| 
 | |
|   bool success = true;
 | |
|   // Try to remove an invalid iface name, this should fail.
 | |
|   EXPECT_TRUE(server_.tearDownClientInterface(
 | |
|       kFateInterfaceNameInvalid, &success).isOk());
 | |
|   EXPECT_FALSE(success);
 | |
|   EXPECT_TRUE(server_.tearDownApInterface(
 | |
|       kFateInterfaceNameInvalid, &success).isOk());
 | |
|   EXPECT_FALSE(success);
 | |
| 
 | |
|   EXPECT_TRUE(server_.tearDownClientInterface(
 | |
|       kFakeInterfaceName, &success).isOk());
 | |
|   EXPECT_TRUE(success);
 | |
| 
 | |
|   EXPECT_TRUE(server_.tearDownApInterface(
 | |
|       kFakeInterfaceName1, &success).isOk());
 | |
|   EXPECT_TRUE(success);
 | |
| }
 | |
| 
 | |
| TEST_F(ServerTest, CanDestroyApAndClientInterfaces) {
 | |
|   sp<IClientInterface> client_if;
 | |
|   sp<IApInterface> ap_if;
 | |
| 
 | |
|   EXPECT_TRUE(server_.createClientInterface(
 | |
|       kFakeInterfaceName, &client_if).isOk());
 | |
|   EXPECT_NE(nullptr, client_if.get());
 | |
| 
 | |
|   EXPECT_TRUE(server_.createApInterface(kFakeInterfaceName1, &ap_if).isOk());
 | |
|   EXPECT_NE(nullptr, ap_if.get());
 | |
| 
 | |
|   // When we tear down the interfaces, we expect the iface to be unloaded.
 | |
|   EXPECT_CALL(*if_tool_, SetUpState(StrEq(kFakeInterfaceName), Eq(false))).Times(2);
 | |
|   EXPECT_CALL(*if_tool_, SetUpState(StrEq(kFakeInterfaceName1), Eq(false))).Times(2);
 | |
| 
 | |
|   EXPECT_TRUE(server_.tearDownInterfaces().isOk());
 | |
| }
 | |
| }  // namespace wificond
 | |
| }  // namespace android
 |