OSDN Git Service

Control hostapd from IApInterface
authorChristopher Wiley <wiley@google.com>
Mon, 18 Jul 2016 22:30:58 +0000 (15:30 -0700)
committerChristopher Wiley <wiley@google.com>
Fri, 22 Jul 2016 19:09:58 +0000 (12:09 -0700)
Add AIDL interfaces, implementation, and tests to wificond.

Bug: 30040724
Test: unitests pass
Test: integration tests pass

Change-Id: I75339d64bf92941de26c7552b6b711cbea00eb80

Android.mk
aidl/android/net/wifi/IApInterface.aidl
ap_interface_binder.cpp
ap_interface_binder.h
ap_interface_impl.cpp
ap_interface_impl.h
server.cpp
server.h
tests/ap_interface_impl_unittest.cpp [new file with mode: 0644]
wificond.rc

index 8bc8a2f..c9df3e6 100644 (file)
@@ -119,8 +119,9 @@ LOCAL_MODULE := wificond_unit_test
 LOCAL_CPPFLAGS := $(wificond_cpp_flags)
 LOCAL_C_INCLUDES := $(wificond_includes)
 LOCAL_SRC_FILES := \
-    tests/main.cpp \
+    tests/ap_interface_impl_unittest.cpp \
     tests/looper_backed_event_loop_unittest.cpp \
+    tests/main.cpp \
     tests/nl80211_attribute_unittest.cpp \
     tests/nl80211_packet_unittest.cpp \
     tests/server_unittest.cpp
index f76610c..c9aa3fe 100644 (file)
@@ -20,4 +20,29 @@ package android.net.wifi;
 // WiFi access point.
 interface IApInterface {
 
+  const int ENCRYPTION_TYPE_NONE = 0;
+  const int ENCRYPTION_TYPE_WPA = 1;
+  const int ENCRYPTION_TYPE_WPA2 = 2;
+
+  // Start up an instance of hostapd associated with this interface.
+  // @return true on success.
+  boolean startHostapd();
+
+  // Stop a previously started instance of hostapd.
+  // @return true on success.
+  boolean stopHostapd();
+
+  // Write out a configuration file for hostapd.  This will be used on the next
+  // successful call to StartHostapd().  Returns true on success.
+  //
+  // @param ssid string of <=32 bytes to use as the SSID for this AP.
+  // @param isHidden True iff the AP should not broadcast its SSID.
+  // @param channel WiFi channel to expose the AP on.
+  // @param encryptionType one of ENCRYPTION_TYPE* above.
+  // @param passphrase string of bytes to use as the passphrase for this AP.
+  //        Ignored if encryptionType is None.
+  // @return true on success.
+  boolean writeHostapdConfig(in byte[] ssid, boolean isHidden, int channel,
+                             int encryptionType, in byte[] passphrase);
+
 }
index 5b5711f..e09e1cb 100644 (file)
 
 #include "wificond/ap_interface_binder.h"
 
+#include <android-base/logging.h>
+#include <wifi_system/hostapd_manager.h>
+
+#include "wificond/ap_interface_impl.h"
+
+using android::wifi_system::HostapdManager;
+
 namespace android {
 namespace wificond {
 
@@ -25,5 +32,60 @@ ApInterfaceBinder::ApInterfaceBinder(ApInterfaceImpl* impl) : impl_{impl} {
 ApInterfaceBinder::~ApInterfaceBinder() {
 }
 
+binder::Status ApInterfaceBinder::startHostapd(bool* out_success) {
+  *out_success = false;
+  if (!impl_) {
+    LOG(WARNING) << "Cannot start hostapd on dead ApInterface.";
+    return binder::Status::ok();
+  }
+  *out_success = impl_->StartHostapd();
+  return binder::Status::ok();
+}
+
+binder::Status ApInterfaceBinder::stopHostapd(bool* out_success) {
+  *out_success = false;
+  if (!impl_) {
+    LOG(WARNING) << "Cannot stop hostapd on dead ApInterface.";
+    return binder::Status::ok();
+  }
+  *out_success = impl_->StopHostapd();
+  return binder::Status::ok();
+}
+
+binder::Status ApInterfaceBinder::writeHostapdConfig(
+    const std::vector<uint8_t>& ssid,
+    bool is_hidden,
+    int32_t channel,
+    int32_t binder_encryption_type,
+    const std::vector<uint8_t>& passphrase,
+    bool* out_success) {
+  *out_success = false;
+  if (!impl_) {
+    LOG(WARNING) << "Cannot set config on dead ApInterface.";
+    return binder::Status::ok();
+  }
+
+  HostapdManager::EncryptionType encryption_type;
+  switch (binder_encryption_type) {
+    case IApInterface::ENCRYPTION_TYPE_NONE:
+      encryption_type = HostapdManager::EncryptionType::kOpen;
+      break;
+    case IApInterface::ENCRYPTION_TYPE_WPA:
+      encryption_type = HostapdManager::EncryptionType::kWpa;
+      break;
+    case IApInterface::ENCRYPTION_TYPE_WPA2:
+      encryption_type = HostapdManager::EncryptionType::kWpa2;
+      break;
+    default:
+      LOG(ERROR) << "Unknown encryption type: " << binder_encryption_type;
+      return binder::Status::ok();
+  }
+
+  *out_success = impl_->WriteHostapdConfig(
+      ssid, is_hidden, channel, encryption_type, passphrase);
+
+  return binder::Status::ok();
+}
+
 }  // namespace wificond
 }  // namespace android
index ace244f..bd966ea 100644 (file)
@@ -36,6 +36,15 @@ class ApInterfaceBinder : public android::net::wifi::BnApInterface {
   // by remote processes are possible.
   void NotifyImplDead() { impl_ = nullptr; }
 
+  binder::Status startHostapd(bool* out_success) override;
+  binder::Status stopHostapd(bool* out_success) override;
+  binder::Status writeHostapdConfig(const std::vector<uint8_t>& ssid,
+                                    bool is_hidden,
+                                    int32_t channel,
+                                    int32_t encryption_type,
+                                    const std::vector<uint8_t>& passphrase,
+                                    bool* out_success) override;
+
  private:
   ApInterfaceImpl* impl_;
 
index 1327f11..3c80da4 100644 (file)
 #include "wificond/ap_interface_binder.h"
 
 using android::net::wifi::IApInterface;
+using android::wifi_system::HostapdManager;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+using EncryptionType = android::wifi_system::HostapdManager::EncryptionType;
 
 namespace android {
 namespace wificond {
 
-ApInterfaceImpl::ApInterfaceImpl() {
+ApInterfaceImpl::ApInterfaceImpl(const string& interface_name,
+                                 unique_ptr<HostapdManager> hostapd_manager)
+    : interface_name_(interface_name),
+      hostapd_manager_(std::move(hostapd_manager)) {
   binder_ = new ApInterfaceBinder(this);
 }
 
@@ -35,5 +44,28 @@ sp<IApInterface> ApInterfaceImpl::GetBinder() const {
   return binder_;
 }
 
+bool ApInterfaceImpl::StartHostapd() {
+  return hostapd_manager_->StartHostapd();
+}
+
+bool ApInterfaceImpl::StopHostapd() {
+  return hostapd_manager_->StopHostapd();
+}
+
+bool ApInterfaceImpl::WriteHostapdConfig(const vector<uint8_t>& ssid,
+                                         bool is_hidden,
+                                         int32_t channel,
+                                         EncryptionType encryption_type,
+                                         const vector<uint8_t>& passphrase) {
+  string config = hostapd_manager_->CreateHostapdConfig(
+      interface_name_, ssid, is_hidden, channel, encryption_type, passphrase);
+
+  if (config.empty()) {
+    return false;
+  }
+
+  return hostapd_manager_->WriteHostapdConfig(config);
+}
+
 }  // namespace wificond
 }  // namespace android
index 7dff654..0781eee 100644 (file)
 #ifndef WIFICOND_AP_INTERFACE_IMPL_H_
 #define WIFICOND_AP_INTERFACE_IMPL_H_
 
+#include <memory>
+#include <string>
+#include <vector>
+
 #include <android-base/macros.h>
+#include <wifi_system/hostapd_manager.h>
 
 #include "android/net/wifi/IApInterface.h"
 
@@ -32,13 +37,25 @@ class ApInterfaceBinder;
 // keep this object separate from the binder representation of itself.
 class ApInterfaceImpl {
  public:
-  ApInterfaceImpl();
+  ApInterfaceImpl(const std::string& interface_name,
+                  std::unique_ptr<wifi_system::HostapdManager> hostapd_manager);
   ~ApInterfaceImpl();
 
   // Get a pointer to the binder representing this ApInterfaceImpl.
   android::sp<android::net::wifi::IApInterface> GetBinder() const;
 
+  bool StartHostapd();
+  bool StopHostapd();
+  bool WriteHostapdConfig(
+      const std::vector<uint8_t>& ssid,
+      bool is_hidden,
+      int32_t channel,
+      wifi_system::HostapdManager::EncryptionType encryption_type,
+      const std::vector<uint8_t>& passphrase);
+
  private:
+  const std::string interface_name_;
+  const std::unique_ptr<wifi_system::HostapdManager> hostapd_manager_;
   android::sp<ApInterfaceBinder> binder_;
 
   DISALLOW_COPY_AND_ASSIGN(ApInterfaceImpl);
index d281613..dff3d44 100644 (file)
 using android::binder::Status;
 using android::sp;
 using android::IBinder;
+using std::string;
 using std::vector;
 using std::unique_ptr;
 using android::net::wifi::IApInterface;
 using android::wifi_hal::DriverTool;
 using android::wifi_system::HalTool;
+using android::wifi_system::HostapdManager;
 using android::wifi_system::InterfaceTool;
 
 namespace android {
 namespace wificond {
+namespace {
+
+const char kNetworkInterfaceName[] = "wlan0";
+
+}  // namespace
 
 Server::Server(unique_ptr<HalTool> hal_tool,
                unique_ptr<InterfaceTool> if_tool,
@@ -48,11 +55,14 @@ Status Server::createApInterface(sp<IApInterface>* created_interface) {
     return Status::ok();
   }
 
-  if (!SetupInterfaceForMode(DriverTool::kFirmwareModeAp)) {
+  string interface_name;
+  if (!SetupInterfaceForMode(DriverTool::kFirmwareModeAp, &interface_name)) {
     return Status::ok();  // Logging was done internally
   }
 
-  unique_ptr<ApInterfaceImpl> ap_interface(new ApInterfaceImpl);
+  unique_ptr<ApInterfaceImpl> ap_interface(new ApInterfaceImpl(
+      interface_name,
+      unique_ptr<HostapdManager>(new HostapdManager)));
   *created_interface = ap_interface->GetBinder();
   ap_interfaces_.push_back(std::move(ap_interface));
   return Status::ok();
@@ -69,7 +79,8 @@ Status Server::tearDownInterfaces() {
   return Status::ok();
 }
 
-bool Server::SetupInterfaceForMode(int mode) {
+bool Server::SetupInterfaceForMode(int mode, string* interface_name) {
+  string result;
   if (!driver_tool_->LoadDriver()) {
     LOG(ERROR) << "Failed to load WiFi driver!";
     return false;
@@ -81,6 +92,7 @@ bool Server::SetupInterfaceForMode(int mode) {
 
   // TODO: Confirm the ap interface is ready for use by checking its
   //       nl80211 published capabilities.
+  *interface_name = kNetworkInterfaceName;
 
   return true;
 }
index 9799748..09510af 100644 (file)
--- a/server.h
+++ b/server.h
@@ -18,6 +18,7 @@
 #define WIFICOND_SERVER_H_
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include <android-base/macros.h>
@@ -46,9 +47,13 @@ class Server : public android::net::wifi::BnWificond {
 
  private:
   // Does the actual work of setting up an interface for a particular mode.
+  //
   // |mode| is one of WIFI_GET_FW_PATH_* defined in hardware_legacy/wifi.h.
+  // |interface_name| is a pointer to a string to store the name of Linux
+  //     network interface that has been setup.
+  //
   // Returns true on success, false otherwise.
-  bool SetupInterfaceForMode(int mode);
+  bool SetupInterfaceForMode(int mode, std::string* interface_name);
 
   const std::unique_ptr<wifi_system::HalTool> hal_tool_;
   const std::unique_ptr<wifi_system::InterfaceTool> if_tool_;
diff --git a/tests/ap_interface_impl_unittest.cpp b/tests/ap_interface_impl_unittest.cpp
new file mode 100644 (file)
index 0000000..51ab7fd
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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 <memory>
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <wifi_system_test/mock_hostapd_manager.h>
+
+#include "wificond/ap_interface_impl.h"
+
+using android::wifi_system::HostapdManager;
+using android::wifi_system::MockHostapdManager;
+using std::unique_ptr;
+using std::vector;
+using testing::NiceMock;
+using testing::Return;
+using testing::Sequence;
+using testing::_;
+
+namespace android {
+namespace wificond {
+namespace {
+
+const char kTestInterfaceName[] = "testwifi0";
+
+class ApInterfaceImplTest : public ::testing::Test {
+ protected:
+  NiceMock<MockHostapdManager>* hostapd_manager_ =
+      new NiceMock<MockHostapdManager>;
+  ApInterfaceImpl ap_interface_{kTestInterfaceName,
+                                unique_ptr<HostapdManager>(hostapd_manager_)};
+};  // class ApInterfaceImplTest
+
+}  // namespace
+
+TEST_F(ApInterfaceImplTest, ShouldReportStartFailure) {
+  EXPECT_CALL(*hostapd_manager_, StartHostapd())
+      .WillOnce(Return(false));
+  EXPECT_FALSE(ap_interface_.StartHostapd());
+}
+
+TEST_F(ApInterfaceImplTest, ShouldReportStartSuccess) {
+  EXPECT_CALL(*hostapd_manager_, StartHostapd())
+      .WillOnce(Return(true));
+  EXPECT_TRUE(ap_interface_.StartHostapd());
+}
+
+TEST_F(ApInterfaceImplTest, ShouldReportStopFailure) {
+  EXPECT_CALL(*hostapd_manager_, StopHostapd())
+      .WillOnce(Return(false));
+  EXPECT_FALSE(ap_interface_.StopHostapd());
+}
+
+TEST_F(ApInterfaceImplTest, ShouldReportStopSuccess) {
+  EXPECT_CALL(*hostapd_manager_, StopHostapd())
+      .WillOnce(Return(true));
+  EXPECT_TRUE(ap_interface_.StopHostapd());
+}
+
+TEST_F(ApInterfaceImplTest, ShouldRejectInvalidConfig) {
+  EXPECT_CALL(*hostapd_manager_, CreateHostapdConfig(_, _, _, _, _, _))
+      .WillOnce(Return(""));
+  EXPECT_CALL(*hostapd_manager_, WriteHostapdConfig(_)).Times(0);
+  EXPECT_FALSE(ap_interface_.WriteHostapdConfig(
+        vector<uint8_t>(),
+        false,
+        0,
+        HostapdManager::EncryptionType::kWpa2,
+        vector<uint8_t>()));
+}
+
+}  // namespace wificond
+}  // namespace android
index 031c73e..c94b561 100644 (file)
@@ -1,2 +1,4 @@
 service wificond /system/bin/wificond
     class main
+    user root
+    group wifi