#include <android-base/logging.h>
+#include "wificond/net/netlink_utils.h"
+
#include "wificond/ap_interface_binder.h"
using android::net::wifi::IApInterface;
ApInterfaceImpl::ApInterfaceImpl(const string& interface_name,
uint32_t interface_index,
+ NetlinkUtils* netlink_utils,
InterfaceTool* if_tool,
HostapdManager* hostapd_manager)
: interface_name_(interface_name),
interface_index_(interface_index),
+ netlink_utils_(netlink_utils),
if_tool_(if_tool),
hostapd_manager_(hostapd_manager),
binder_(new ApInterfaceBinder(this)) {
bool ApInterfaceImpl::StopHostapd() {
// Drop SIGKILL on hostapd.
- bool success = hostapd_manager_->StopHostapd();
+ if (!hostapd_manager_->StopHostapd()) {
+ // Logging was done internally.
+ return false;
+ }
+
+ // Take down the interface.
+ if (!if_tool_->SetUpState(interface_name_.c_str(), false)) {
+ // Logging was done internally.
+ return false;
+ }
- // Take down the interface. This has the pleasant side effect of
- // letting the driver know that we don't want any lingering AP logic
- // running in the driver.
- success = if_tool_->SetUpState(interface_name_.c_str(), false) && success;
+ // Since wificond SIGKILLs hostapd, hostapd has no chance to handle
+ // the cleanup.
+ // Besides taking down the interface, we also need to set the interface mode
+ // back to station mode for the cleanup.
+ if (!netlink_utils_->SetInterfaceMode(interface_index_,
+ NetlinkUtils::STATION_MODE)) {
+ LOG(ERROR) << "Failed to set interface back to station mode";
+ return false;
+ }
- return success;
+ return true;
}
bool ApInterfaceImpl::WriteHostapdConfig(const vector<uint8_t>& ssid,
namespace wificond {
class ApInterfaceBinder;
+class NetlinkUtils;
// Holds the guts of how we control network interfaces capable of exposing an AP
// via hostapd. Because remote processes may hold on to the corresponding
public:
ApInterfaceImpl(const std::string& interface_name,
uint32_t interface_index,
+ NetlinkUtils* netlink_utils,
wifi_system::InterfaceTool* if_tool,
wifi_system::HostapdManager* hostapd_manager);
~ApInterfaceImpl();
private:
const std::string interface_name_;
const uint32_t interface_index_;
+ NetlinkUtils* const netlink_utils_;
wifi_system::InterfaceTool* const if_tool_;
wifi_system::HostapdManager* const hostapd_manager_;
const android::sp<ApInterfaceBinder> binder_;
return false;
}
+bool NetlinkUtils::SetInterfaceMode(uint32_t interface_index,
+ InterfaceMode mode) {
+ uint32_t set_to_mode = NL80211_IFTYPE_UNSPECIFIED;
+ if (mode == STATION_MODE) {
+ set_to_mode = NL80211_IFTYPE_STATION;
+ } else {
+ LOG(ERROR) << "Unexpected mode for interface with index: "
+ << interface_index;
+ return false;
+ }
+ NL80211Packet set_interface_mode(
+ netlink_manager_->GetFamilyId(),
+ NL80211_CMD_SET_INTERFACE,
+ netlink_manager_->GetSequenceNumber(),
+ getpid());
+ // Force an ACK response upon success.
+ set_interface_mode.AddFlag(NLM_F_ACK);
+
+ set_interface_mode.AddAttribute(
+ NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index));
+ set_interface_mode.AddAttribute(
+ NL80211Attr<uint32_t>(NL80211_ATTR_IFTYPE, set_to_mode));
+
+ if (!netlink_manager_->SendMessageAndGetAck(set_interface_mode)) {
+ LOG(ERROR) << "NL80211_CMD_SET_INTERFACE failed";
+ return false;
+ }
+
+ return true;
+}
bool NetlinkUtils::GetWiphyInfo(
uint32_t wiphy_index,
// Provides NL80211 helper functions.
class NetlinkUtils {
public:
+ // Currently we only support setting the interface to STATION mode.
+ // This is used for cleaning up interface after KILLING hostapd.
+ enum InterfaceMode{
+ STATION_MODE
+ };
+
explicit NetlinkUtils(NetlinkManager* netlink_manager);
virtual ~NetlinkUtils();
uint32_t* index,
std::vector<uint8_t>* mac_addr);
+ // Set the mode of interface.
+ // |interface_index| is the interface index.
+ // |mode| is one of the values in |enum InterfaceMode|.
+ // Returns true on success.
+ virtual bool SetInterfaceMode(uint32_t interface_index,
+ InterfaceMode mode);
+
// Get wiphy capability information from kernel.
// Returns true on success.
virtual bool GetWiphyInfo(uint32_t wiphy_index,
unique_ptr<ApInterfaceImpl> ap_interface(new ApInterfaceImpl(
interface_name,
interface_index,
+ netlink_utils_,
if_tool_.get(),
hostapd_manager_.get()));
*created_interface = ap_interface->GetBinder();
#include <wifi_system_test/mock_hostapd_manager.h>
#include <wifi_system_test/mock_interface_tool.h>
+#include "wificond/tests/mock_netlink_manager.h"
+#include "wificond/tests/mock_netlink_utils.h"
+
#include "wificond/ap_interface_impl.h"
using android::wifi_system::HostapdManager;
new NiceMock<MockInterfaceTool>};
unique_ptr<NiceMock<MockHostapdManager>> hostapd_manager_{
new NiceMock<MockHostapdManager>};
+ unique_ptr<NiceMock<MockNetlinkManager>> netlink_manager_{
+ new NiceMock<MockNetlinkManager>()};
+ unique_ptr<NiceMock<MockNetlinkUtils>> netlink_utils_{
+ new NiceMock<MockNetlinkUtils>(netlink_manager_.get())};
+
ApInterfaceImpl ap_interface_{kTestInterfaceName,
kTestInterfaceIndex,
+ netlink_utils_.get(),
if_tool_.get(),
hostapd_manager_.get()};
}; // class ApInterfaceImplTest
.WillOnce(Return(true));
EXPECT_CALL(*if_tool_, SetUpState(StrEq(kTestInterfaceName), false))
.WillOnce(Return(true));
+ EXPECT_CALL(*netlink_utils_, SetInterfaceMode(
+ kTestInterfaceIndex,
+ NetlinkUtils::STATION_MODE)).WillOnce(Return(true));
EXPECT_TRUE(ap_interface_.StopHostapd());
testing::Mock::VerifyAndClearExpectations(if_tool_.get());
}
MOCK_METHOD1(GetWiphyIndex, bool(uint32_t* out_wiphy_index));
MOCK_METHOD1(UnsubscribeMlmeEvent, void(uint32_t interface_index));
MOCK_METHOD1(UnsubscribeRegDomainChange, void(uint32_t wiphy_index));
+ MOCK_METHOD2(SetInterfaceMode,
+ bool(uint32_t interface_index, InterfaceMode mode));
MOCK_METHOD2(SubscribeMlmeEvent,
void(uint32_t interface_index,
MlmeEventHandler* handler));
return NL80211Packet(data);
}
+NL80211Packet CreateControlMessageAck() {
+ return CreateControlMessageError(0);
+}
+
} // namespace
class NetlinkUtilsTest : public ::testing::Test {
EXPECT_FALSE(netlink_utils_->GetWiphyIndex(&wiphy_index));
}
+TEST_F(NetlinkUtilsTest, CanSetIntrerfaceMode) {
+ // Mock a ACK response from kernel.
+ vector<NL80211Packet> response = {CreateControlMessageAck()};
+
+ EXPECT_CALL(*netlink_manager_, SendMessageAndGetResponses(_, _)).
+ WillOnce(DoAll(MakeupResponse(response), Return(true)));
+
+ EXPECT_TRUE(netlink_utils_->SetInterfaceMode(kFakeInterfaceIndex,
+ NetlinkUtils::STATION_MODE));
+}
+
+TEST_F(NetlinkUtilsTest, CanHandleSetIntrerfaceModeError) {
+ // Mock an error response from kernel.
+ vector<NL80211Packet> response = {CreateControlMessageError(kFakeErrorCode)};
+
+ EXPECT_CALL(*netlink_manager_, SendMessageAndGetResponses(_, _)).
+ WillOnce(DoAll(MakeupResponse(response), Return(true)));
+
+ EXPECT_FALSE(netlink_utils_->SetInterfaceMode(kFakeInterfaceIndex,
+ NetlinkUtils::STATION_MODE));
+}
+
TEST_F(NetlinkUtilsTest, CanGetInterfaceInfo) {
NL80211Packet new_interface(
netlink_manager_->GetFamilyId(),