return true;
}
-bool NetlinkUtils::GetInterfaceInfo(uint32_t wiphy_index,
- string* name,
- uint32_t* index,
- vector<uint8_t>* mac_addr) {
- NL80211Packet get_interface(
+bool NetlinkUtils::GetInterfaces(uint32_t wiphy_index,
+ vector<InterfaceInfo>* interface_info) {
+ NL80211Packet get_interfaces(
netlink_manager_->GetFamilyId(),
NL80211_CMD_GET_INTERFACE,
netlink_manager_->GetSequenceNumber(),
getpid());
- get_interface.AddFlag(NLM_F_DUMP);
- NL80211Attr<uint32_t> wiphy(NL80211_ATTR_WIPHY, wiphy_index);
- get_interface.AddAttribute(wiphy);
+ get_interfaces.AddFlag(NLM_F_DUMP);
+ get_interfaces.AddAttribute(
+ NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY, wiphy_index));
vector<unique_ptr<const NL80211Packet>> response;
- if (!netlink_manager_->SendMessageAndGetResponses(get_interface, &response)) {
+ if (!netlink_manager_->SendMessageAndGetResponses(get_interfaces, &response)) {
LOG(ERROR) << "NL80211_CMD_GET_INTERFACE dump failed";
return false;
}
return false;
}
+ // In some situations, it has been observed that the kernel tells us
+ // about a pseudo interface that does not have a real netdev. In this
+ // case, responses will have a NL80211_ATTR_WDEV, and not the expected
+ // IFNAME/IFINDEX. In this case we just skip these pseudo interfaces.
+ uint32_t if_index;
+ if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
+ LOG(DEBUG) << "Failed to get interface index";
+ continue;
+ }
+
// Today we don't check NL80211_ATTR_IFTYPE because at this point of time
// driver always reports that interface is in STATION mode. Even when we
// are asking interfaces infomation on behalf of tethering, it is still so
string if_name;
if (!packet->GetAttributeValue(NL80211_ATTR_IFNAME, &if_name)) {
- // In some situations, it has been observed that the kernel tells us
- // about a pseudo-device that does not have a real netdev. In this
- // case, responses will have a NL80211_ATTR_WDEV, and not the expected
- // IFNAME.
- LOG(DEBUG) << "Failed to get interface name";
- continue;
- }
- if (if_name == "p2p0") {
- LOG(DEBUG) << "Driver may tell a lie that p2p0 is in STATION mode,"
- <<" we need to blacklist it.";
- continue;
- }
-
- uint32_t if_index;
- if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
- LOG(DEBUG) << "Failed to get interface index";
+ LOG(WARNING) << "Failed to get interface name";
continue;
}
vector<uint8_t> if_mac_addr;
if (!packet->GetAttributeValue(NL80211_ATTR_MAC, &if_mac_addr)) {
- LOG(DEBUG) << "Failed to get interface mac address";
+ LOG(WARNING) << "Failed to get interface mac address";
continue;
}
- *name = if_name;
- *index = if_index;
- *mac_addr = if_mac_addr;
- return true;
+ interface_info->emplace_back(if_index, if_name, if_mac_addr);
}
- LOG(ERROR) << "Failed to get expected interface info from kernel";
- return false;
+ return true;
}
bool NetlinkUtils::SetInterfaceMode(uint32_t interface_index,
namespace android {
namespace wificond {
+struct InterfaceInfo {
+ InterfaceInfo() = default;
+ InterfaceInfo(uint32_t index_,
+ const std::string name_,
+ const std::vector<uint8_t> mac_address_)
+ : index(index_),
+ name(name_),
+ mac_address(mac_address_) {}
+ // Index of this interface.
+ uint32_t index;
+ // Name of this interface.
+ std::string name;
+ // MAC address of this interface.
+ std::vector<uint8_t> mac_address;
+};
+
struct BandInfo {
BandInfo() = default;
BandInfo(std::vector<uint32_t>& band_2g_,
// Returns true on success.
virtual bool GetWiphyIndex(uint32_t* out_wiphy_index);
- // Get wifi interface info from kernel.
+ // Get wifi interfaces info from kernel.
// |wiphy_index| is the wiphy index we get using GetWiphyIndex().
+ // |interface_info| returns a vector of InterfaceInfo structs with
+ // information about all existing interfaces.
// Returns true on success.
- virtual bool GetInterfaceInfo(uint32_t wiphy_index,
- std::string* name,
- uint32_t* index,
- std::vector<uint8_t>* mac_addr);
+ virtual bool GetInterfaces(uint32_t wiphy_index,
+ std::vector<InterfaceInfo>* interface_info);
// Set the mode of interface.
// |interface_index| is the interface index.
}
Status Server::createApInterface(sp<IApInterface>* created_interface) {
- string interface_name;
- uint32_t interface_index;
- vector<uint8_t> interface_mac_addr;
- if (!SetupInterface(&interface_name,
- &interface_index,
- &interface_mac_addr)) {
+ InterfaceInfo interface;
+ if (!SetupInterface(&interface)) {
return Status::ok(); // Logging was done internally
}
unique_ptr<ApInterfaceImpl> ap_interface(new ApInterfaceImpl(
- interface_name,
- interface_index,
+ interface.name,
+ interface.index,
netlink_utils_,
if_tool_.get(),
hostapd_manager_.get()));
}
Status Server::createClientInterface(sp<IClientInterface>* created_interface) {
- string interface_name;
- uint32_t interface_index;
- vector<uint8_t> interface_mac_addr;
- if (!SetupInterface(&interface_name,
- &interface_index,
- &interface_mac_addr)) {
+ InterfaceInfo interface;
+ if (!SetupInterface(&interface)) {
return Status::ok(); // Logging was done internally
}
unique_ptr<ClientInterfaceImpl> client_interface(new ClientInterfaceImpl(
wiphy_index_,
- interface_name,
- interface_index,
- interface_mac_addr,
+ interface.name,
+ interface.index,
+ interface.mac_address,
if_tool_.get(),
supplicant_manager_.get(),
netlink_utils_,
}
ap_interfaces_.clear();
+ MarkDownAllInterfaces();
+
netlink_utils_->UnsubscribeRegDomainChange(wiphy_index_);
return Status::ok();
return binder::Status::ok();
}
+void Server::MarkDownAllInterfaces() {
+ uint32_t wiphy_index;
+ vector<InterfaceInfo> interfaces;
+ if (netlink_utils_->GetWiphyIndex(&wiphy_index) &&
+ netlink_utils_->GetInterfaces(wiphy_index, &interfaces)) {
+ for (InterfaceInfo& interface : interfaces) {
+ if_tool_->SetUpState(interface.name.c_str(), false);
+ }
+ }
+}
+
void Server::CleanUpSystemState() {
supplicant_manager_->StopSupplicant();
hostapd_manager_->StopHostapd();
-
- uint32_t phy_index = 0;
- uint32_t if_index = 0;
- vector<uint8_t> mac;
- string if_name;
- if (netlink_utils_->GetWiphyIndex(&phy_index) &&
- netlink_utils_->GetInterfaceInfo(phy_index,
- &if_name,
- &if_index,
- &mac)) {
- // If the kernel knows about a network interface, mark it as down.
- // This prevents us from beaconing as an AP, or remaining associated
- // as a client.
- if_tool_->SetUpState(if_name.c_str(), false);
- }
+ MarkDownAllInterfaces();
}
-bool Server::SetupInterface(string* interface_name,
- uint32_t* interface_index,
- vector<uint8_t>* interface_mac_addr) {
+bool Server::SetupInterface(InterfaceInfo* interface) {
if (!ap_interfaces_.empty() || !client_interfaces_.empty()) {
// In the future we may support multiple interfaces at once. However,
// today, we support just one.
this,
_1));
- if (!netlink_utils_->GetInterfaceInfo(wiphy_index_,
- interface_name,
- interface_index,
- interface_mac_addr)) {
- LOG(ERROR) << "Failed to get interface info from kernel";
+ vector<InterfaceInfo> interfaces;
+ if (!netlink_utils_->GetInterfaces(wiphy_index_, &interfaces)) {
+ LOG(ERROR) << "Failed to get interfaces info from kernel";
return false;
}
- return true;
+ for (InterfaceInfo& iface : interfaces) {
+ // Some kernel/driver uses station type for p2p interface.
+ // In that case we can only rely on hard-coded name to exclude
+ // p2p interface from station interfaces.
+ if (iface.name != "p2p0") {
+ *interface = iface;
+ return true;
+ }
+ }
+
+ LOG(ERROR) << "No usable interface found";
+ return false;
}
bool Server::RefreshWiphyIndex() {
class NetlinkUtils;
class ScanUtils;
+struct InterfaceInfo;
+
class Server : public android::net::wifi::BnWificond {
public:
Server(std::unique_ptr<wifi_system::InterfaceTool> if_tool,
// interface on behalf of createApInterace(), it is Hostapd that configure
// the interface to Ap mode later.
// Returns true on success, false otherwise.
- bool SetupInterface(std::string* interface_name,
- uint32_t* interface_index,
- std::vector<uint8_t>* interface_mac_addr);
+ bool SetupInterface(InterfaceInfo* interface);
bool RefreshWiphyIndex();
void LogSupportedBands();
void OnRegDomainChanged(std::string& country_code);
android::sp<android::net::wifi::IClientInterface> network_interface);
void BroadcastApInterfaceTornDown(
android::sp<android::net::wifi::IApInterface> network_interface);
+ void MarkDownAllInterfaces();
const std::unique_ptr<wifi_system::InterfaceTool> if_tool_;
const std::unique_ptr<wifi_system::SupplicantManager> supplicant_manager_;
void(uint32_t wiphy_index,
OnRegDomainChangedHandler handler));
- MOCK_METHOD4(GetInterfaceInfo,
+ MOCK_METHOD2(GetInterfaces,
bool(uint32_t wiphy_index,
- std::string* name,
- uint32_t* index,
- std::vector<uint8_t>* mac_address));
+ std::vector<InterfaceInfo>* interfaces));
MOCK_METHOD4(GetWiphyInfo,
bool(uint32_t wiphy_index,
BandInfo* band_info,
constexpr int kFakeErrorCode = EIO;
const char kFakeInterfaceName[] = "testif0";
const uint32_t kFakeInterfaceIndex = 34;
+const uint32_t kFakeInterfaceIndex1 = 36;
const uint8_t kFakeInterfaceMacAddress[] = {0x45, 0x54, 0xad, 0x67, 0x98, 0xf6};
+const uint8_t kFakeInterfaceMacAddress1[] = {0x05, 0x04, 0xef, 0x27, 0x12, 0xff};
// Currently, control messages are only created by the kernel and sent to us.
// Therefore NL80211Packet doesn't have corresponding constructor.
NetlinkUtils::STATION_MODE));
}
-TEST_F(NetlinkUtilsTest, CanGetInterfaceInfo) {
+TEST_F(NetlinkUtilsTest, CanGetInterfaces) {
NL80211Packet new_interface(
netlink_manager_->GetFamilyId(),
NL80211_CMD_NEW_INTERFACE,
EXPECT_CALL(*netlink_manager_, SendMessageAndGetResponses(_, _)).
WillOnce(DoAll(MakeupResponse(response), Return(true)));
- string interface_name;
- uint32_t interface_index;
- vector<uint8_t> interface_mac_addr;
- EXPECT_TRUE(netlink_utils_->GetInterfaceInfo(kFakeWiphyIndex,
- &interface_name,
- &interface_index,
- &interface_mac_addr));
- EXPECT_EQ(string(kFakeInterfaceName), interface_name);
- EXPECT_EQ(kFakeInterfaceIndex, interface_index);
- EXPECT_EQ(if_mac_addr, interface_mac_addr);
+ vector<InterfaceInfo> interfaces;
+ EXPECT_TRUE(netlink_utils_->GetInterfaces(kFakeWiphyIndex, &interfaces));
+ EXPECT_TRUE(interfaces.size() == 1);
+ EXPECT_EQ(kFakeInterfaceIndex, interfaces[0].index);
+ EXPECT_EQ(string(kFakeInterfaceName), interfaces[0].name);
+ EXPECT_EQ(if_mac_addr, interfaces[0].mac_address);
}
-TEST_F(NetlinkUtilsTest, HandlesPseudoDevicesInInterfaceInfoQuery) {
- // Some kernels will have extra responses ahead of the expected packet.
+TEST_F(NetlinkUtilsTest, SkipsPseudoDevicesWhenGetInterfaces) {
+ // This might be a psuedo p2p interface without any interface index/name
+ // attributes.
NL80211Packet psuedo_interface(
netlink_manager_->GetFamilyId(),
NL80211_CMD_NEW_INTERFACE,
psuedo_interface.AddAttribute(NL80211Attr<uint64_t>(
NL80211_ATTR_WDEV, 0));
- // This is the packet we're looking for
+ // This is a regular client interface.
NL80211Packet expected_interface(
netlink_manager_->GetFamilyId(),
NL80211_CMD_NEW_INTERFACE,
EXPECT_CALL(*netlink_manager_, SendMessageAndGetResponses(_, _)).
WillOnce(DoAll(MakeupResponse(response), Return(true)));
- string interface_name;
- uint32_t interface_index;
- vector<uint8_t> interface_mac_addr;
- EXPECT_TRUE(netlink_utils_->GetInterfaceInfo(
- kFakeWiphyIndex, &interface_name, &interface_index, &interface_mac_addr));
- EXPECT_EQ(string(kFakeInterfaceName), interface_name);
- EXPECT_EQ(kFakeInterfaceIndex, interface_index);
- EXPECT_EQ(if_mac_addr, interface_mac_addr);
+ vector<InterfaceInfo> interfaces;
+ EXPECT_TRUE(netlink_utils_->GetInterfaces(kFakeWiphyIndex, &interfaces));
+ EXPECT_TRUE(interfaces.size() == 1);
+ EXPECT_EQ(kFakeInterfaceIndex, interfaces[0].index);
+ EXPECT_EQ(string(kFakeInterfaceName), interfaces[0].name);
+ EXPECT_EQ(if_mac_addr, interfaces[0].mac_address);
}
-TEST_F(NetlinkUtilsTest, HandleP2p0WhenGetInterfaceInfo) {
+TEST_F(NetlinkUtilsTest, HandleP2p0WhenGetInterfaces) {
NL80211Packet new_interface(
netlink_manager_->GetFamilyId(),
NL80211_CMD_NEW_INTERFACE,
NL80211Attr<string> if_name_attr(NL80211_ATTR_IFNAME, string(kFakeInterfaceName));
new_interface.AddAttribute(if_name_attr);
// Insert interface index attribute.
- NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, kFakeInterfaceIndex);
- new_interface.AddAttribute(if_index_attr);
+ new_interface.AddAttribute(
+ NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, kFakeInterfaceIndex));
// Insert mac address attribute.
- std::vector<uint8_t> if_mac_addr;
- if_mac_addr.assign(
+ std::vector<uint8_t> if_mac_addr(
kFakeInterfaceMacAddress,
kFakeInterfaceMacAddress + sizeof(kFakeInterfaceMacAddress));
- NL80211Attr<vector<uint8_t>> if_mac_attr(NL80211_ATTR_MAC, if_mac_addr);
- new_interface.AddAttribute(if_mac_attr);
+ new_interface.AddAttribute(
+ NL80211Attr<vector<uint8_t>>(NL80211_ATTR_MAC, if_mac_addr));
// Create a new interface packet for p2p0.
NL80211Packet new_interface_p2p0(
NL80211_CMD_NEW_INTERFACE,
netlink_manager_->GetSequenceNumber(),
getpid());
- NL80211Attr<string> if_name_attr_p2p0(NL80211_ATTR_IFNAME, "p2p0");
- new_interface_p2p0.AddAttribute(if_name_attr_p2p0);
+
+ // Insert interface name attribute.
+ new_interface_p2p0.AddAttribute(
+ NL80211Attr<string>(NL80211_ATTR_IFNAME, "p2p0"));
+ // Insert interface index attribute.
+ new_interface_p2p0.AddAttribute(
+ NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, kFakeInterfaceIndex1));
+ // Insert mac address attribute.
+ std::vector<uint8_t> if_mac_addr_p2p(
+ kFakeInterfaceMacAddress1,
+ kFakeInterfaceMacAddress1 + sizeof(kFakeInterfaceMacAddress1));
+ new_interface_p2p0.AddAttribute(
+ NL80211Attr<vector<uint8_t>>(NL80211_ATTR_MAC, if_mac_addr_p2p));
+
// Mock response from kernel, including 2 interfaces.
vector<NL80211Packet> response = {new_interface_p2p0, new_interface};
EXPECT_CALL(*netlink_manager_, SendMessageAndGetResponses(_, _)).
WillOnce(DoAll(MakeupResponse(response), Return(true)));
- string interface_name;
- uint32_t interface_index;
- vector<uint8_t> interface_mac_addr;
- EXPECT_TRUE(netlink_utils_->GetInterfaceInfo(kFakeWiphyIndex,
- &interface_name,
- &interface_index,
- &interface_mac_addr));
- EXPECT_EQ(string(kFakeInterfaceName), interface_name);
- EXPECT_EQ(kFakeInterfaceIndex, interface_index);
- EXPECT_EQ(if_mac_addr, interface_mac_addr);
+ vector<InterfaceInfo> interfaces;
+ EXPECT_TRUE(netlink_utils_->GetInterfaces(kFakeWiphyIndex, &interfaces));
+ EXPECT_TRUE(interfaces.size() == 2);
+
+ EXPECT_EQ(kFakeInterfaceIndex1, interfaces[0].index);
+ EXPECT_EQ(string("p2p0"), interfaces[0].name);
+ EXPECT_EQ(if_mac_addr_p2p, interfaces[0].mac_address);
+
+ EXPECT_EQ(kFakeInterfaceIndex, interfaces[1].index);
+ EXPECT_EQ(string(kFakeInterfaceName), interfaces[1].name);
+ EXPECT_EQ(if_mac_addr, interfaces[1].mac_address);
}
-TEST_F(NetlinkUtilsTest, CanHandleGetInterfaceInfoError) {
+TEST_F(NetlinkUtilsTest, CanHandleGetInterfacesError) {
// Mock an error response from kernel.
vector<NL80211Packet> response = {CreateControlMessageError(kFakeErrorCode)};
EXPECT_CALL(*netlink_manager_, SendMessageAndGetResponses(_, _)).
WillOnce(DoAll(MakeupResponse(response), Return(true)));
- string interface_name;
- uint32_t interface_index;
- vector<uint8_t> interface_mac_addr;
- EXPECT_FALSE(netlink_utils_->GetInterfaceInfo(kFakeWiphyIndex,
- &interface_name,
- &interface_index,
- &interface_mac_addr));
+ vector<InterfaceInfo> interfaces;
+ EXPECT_FALSE(netlink_utils_->GetInterfaces(kFakeWiphyIndex, &interfaces));
}
TEST_F(NetlinkUtilsTest, CanGetWiphyInfo) {
using android::wifi_system::MockSupplicantManager;
using android::wifi_system::SupplicantManager;
using std::unique_ptr;
+using std::vector;
+using testing::Invoke;
using testing::NiceMock;
using testing::Return;
using testing::Sequence;
using testing::_;
+using namespace std::placeholders;
+
namespace android {
namespace wificond {
namespace {
+const char kFakeInterfaceName[] = "testif0";
+const uint32_t kFakeInterfaceIndex = 34;
+const uint32_t kFakeInterfaceIndex1 = 36;
+const uint8_t kFakeInterfaceMacAddress[] = {0x45, 0x54, 0xad, 0x67, 0x98, 0xf6};
+const uint8_t kFakeInterfaceMacAddress1[] = {0x05, 0x04, 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 (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_, SetWifiUpState(_)).WillByDefault(Return(true));
ON_CALL(*netlink_utils_, GetWiphyIndex(_)).WillByDefault(Return(true));
- ON_CALL(*netlink_utils_, GetInterfaceInfo(_, _, _, _))
- .WillByDefault(Return(true));
+ ON_CALL(*netlink_utils_, GetInterfaces(_, _))
+ .WillByDefault(Invoke(bind(
+ MockGetInterfacesResponse, mock_interfaces, true, _1, _2)));
}
NiceMock<MockInterfaceTool>* if_tool_ = new NiceMock<MockInterfaceTool>;
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,
+ std::string(kFakeInterfaceName),
+ vector<uint8_t>(
+ kFakeInterfaceMacAddress,
+ kFakeInterfaceMacAddress + sizeof(kFakeInterfaceMacAddress))),
+ // p2p interface
+ InterfaceInfo(
+ kFakeInterfaceIndex1,
+ "p2p0",
+ vector<uint8_t>(
+ kFakeInterfaceMacAddress1,
+ kFakeInterfaceMacAddress1 + sizeof(kFakeInterfaceMacAddress1)))
+ };
Server server_{unique_ptr<InterfaceTool>(if_tool_),
unique_ptr<SupplicantManager>(supplicant_manager_),
TEST_F(ServerTest, CanSetUpApInterface) {
sp<IApInterface> ap_if;
- Sequence sequence;
- EXPECT_CALL(*netlink_utils_, GetWiphyIndex(_))
- .InSequence(sequence)
- .WillOnce(Return(true));
EXPECT_CALL(*netlink_utils_, SubscribeRegDomainChange(_, _));
- EXPECT_CALL(*netlink_utils_, GetInterfaceInfo(_, _, _, _))
- .InSequence(sequence)
- .WillOnce(Return(true));
EXPECT_TRUE(server_.createApInterface(&ap_if).isOk());
EXPECT_NE(nullptr, ap_if.get());
TEST_F(ServerTest, DoesNotSupportMultipleInterfaces) {
sp<IApInterface> ap_if;
- EXPECT_CALL(*netlink_utils_, GetWiphyIndex(_)).Times(1);
- EXPECT_CALL(*netlink_utils_, GetInterfaceInfo(_, _, _, _)).Times(1);
EXPECT_TRUE(server_.createApInterface(&ap_if).isOk());
EXPECT_NE(nullptr, ap_if.get());
TEST_F(ServerTest, CanDestroyInterfaces) {
sp<IApInterface> ap_if;
- EXPECT_CALL(*netlink_utils_, GetWiphyIndex(_)).Times(2);
- EXPECT_CALL(*netlink_utils_, GetInterfaceInfo(_, _, _, _)).Times(2);
EXPECT_TRUE(server_.createApInterface(&ap_if).isOk());