summaryrefslogtreecommitdiff
path: root/libwifi_system/hostapd_manager.cpp
diff options
context:
space:
mode:
authorChristopher Wiley <wiley@google.com>2016-07-14 16:40:58 -0700
committerChristopher Wiley <wiley@google.com>2016-07-18 13:58:21 -0700
commit944db7cbdafa91279b40dd8a7737307e49cf711e (patch)
tree3b6cb1aef535ccb223437a8b27a622d14de0a0d2 /libwifi_system/hostapd_manager.cpp
parent3efd47ff5e926cc1fa042e288e129df10fa4ec83 (diff)
downloadwifi-944db7cbdafa91279b40dd8a7737307e49cf711e.tar.gz
Move hostapd management logic to libwifi-system
This is the logic that existed in netd, but moved into a mockable C++ object and formulated to support unittesting the config file generation. Bug: 30040724 Test: unit tests pass, data for tests extracted from config files generated by existing netd code. Test: netd continues to be able to set up APs for tethering using libwifi-system rather than previous code. Test: No SELinux policy violations during/after setup. Test: Can sign in to network backed by hostapd started by netd using libwifi-system. Change-Id: I1156c494fc889a3fdf14182b11c7697d93fdf586
Diffstat (limited to 'libwifi_system/hostapd_manager.cpp')
-rw-r--r--libwifi_system/hostapd_manager.cpp202
1 files changed, 202 insertions, 0 deletions
diff --git a/libwifi_system/hostapd_manager.cpp b/libwifi_system/hostapd_manager.cpp
new file mode 100644
index 000000000..889fd6946
--- /dev/null
+++ b/libwifi_system/hostapd_manager.cpp
@@ -0,0 +1,202 @@
+/*
+ * 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 "wifi_system/hostapd_manager.h"
+
+#include <iomanip>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <cutils/properties.h>
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+#include <private/android_filesystem_config.h>
+
+#include "wifi_system/wifi.h"
+
+using android::base::StringPrintf;
+using android::base::WriteStringToFile;
+using std::string;
+using std::vector;
+using std::stringstream;
+
+namespace android {
+namespace wifi_system {
+namespace {
+
+const int kDefaultApChannel = 6;
+const char kHostapdServiceName[] = "hostapd";
+const char kHostapdConfigFilePath[] = "/data/misc/wifi/hostapd.conf";
+
+string GeneratePsk(const vector<uint8_t>& ssid,
+ const vector<uint8_t>& passphrase) {
+ string result;
+ unsigned char psk[SHA256_DIGEST_LENGTH];
+
+ // Use the PKCS#5 PBKDF2 with 4096 iterations
+ if (PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(passphrase.data()),
+ passphrase.size(),
+ ssid.data(), ssid.size(),
+ 4096, sizeof(psk), psk) != 1) {
+ LOG(ERROR) << "Cannot generate PSK using PKCS#5 PBKDF2";
+ return result;
+ }
+
+ stringstream ss;
+ ss << std::hex;
+ ss << std::setfill('0');
+ for (int j = 0; j < SHA256_DIGEST_LENGTH; j++) {
+ ss << std::setw(2) << static_cast<unsigned int>(psk[j]);
+ }
+ result = ss.str();
+
+ return result;
+}
+
+} // namespace
+
+bool HostapdManager::StartHostapd() {
+ if (hostapd_is_running_) {
+ LOG(ERROR) << "SoftAP is already running";
+ return false;
+ }
+
+ if (ensure_entropy_file_exists() < 0) {
+ LOG(WARNING) << "Wi-Fi entropy file was not created";
+ }
+
+ if (property_set("ctl.start", kHostapdServiceName) != 0) {
+ LOG(ERROR) << "Failed to start SoftAP";
+ return false;
+ }
+
+ LOG(DEBUG) << "SoftAP started successfully";
+ hostapd_is_running_ = true;
+ return true;
+}
+
+bool HostapdManager::IsHostapdRunning() {
+ return hostapd_is_running_;
+}
+
+bool HostapdManager::StopHostapd() {
+ if (!hostapd_is_running_) {
+ LOG(DEBUG) << "SoftAP is not running";
+ return true; // Not really an error, hostapd is already stopped.
+ }
+
+ LOG(DEBUG) << "Stopping the SoftAP service...";
+
+ if (property_set("ctl.stop", kHostapdServiceName) < 0) {
+ LOG(ERROR) << "Failed to stop hostapd service!";
+ return false;
+ }
+
+ LOG(DEBUG) << "SoftAP stopped successfully";
+ hostapd_is_running_ = false;
+ return true;
+}
+
+bool HostapdManager::WriteHostapdConfig(const string& config) {
+ if (!WriteStringToFile(config, kHostapdConfigFilePath,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+ AID_SYSTEM, AID_WIFI)) {
+ int error = errno;
+ LOG(ERROR) << "Cannot write hostapd config to \""
+ << kHostapdConfigFilePath << "\": " << strerror(error);
+ return false;
+ }
+ return true;
+}
+
+string HostapdManager::CreateHostapdConfig(
+ const string& interface_name,
+ const vector<uint8_t> ssid,
+ bool is_hidden,
+ int channel,
+ EncryptionType encryption_type,
+ const vector<uint8_t> passphrase) {
+ string result;
+
+ if (channel < 0) {
+ channel = kDefaultApChannel;
+ }
+
+ if (ssid.size() > 32) {
+ LOG(ERROR) << "SSIDs must be <= 32 bytes long";
+ return result;
+ }
+
+ stringstream ss;
+ ss << std::hex;
+ ss << std::setfill('0');
+ for (uint8_t b : ssid) {
+ ss << std::setw(2) << static_cast<unsigned int>(b);
+ }
+ const string ssid_as_string = ss.str();
+
+ string encryption_config;
+ if (encryption_type != EncryptionType::kOpen) {
+ string psk = GeneratePsk(ssid, passphrase);
+ if (psk.empty()) {
+ return result;
+ }
+ if (encryption_type == EncryptionType::kWpa) {
+ encryption_config = StringPrintf("wpa=3\n"
+ "wpa_pairwise=TKIP CCMP\n"
+ "wpa_psk=%s\n", psk.c_str());
+ } else if (encryption_type == EncryptionType::kWpa2) {
+ encryption_config = StringPrintf("wpa=2\n"
+ "rsn_pairwise=CCMP\n"
+ "wpa_psk=%s\n", psk.c_str());
+ } else {
+ using encryption_t = std::underlying_type<EncryptionType>::type;
+ LOG(ERROR) << "Unknown encryption type ("
+ << static_cast<encryption_t>(encryption_type)
+ << ")";
+ return result;
+ }
+ }
+
+ result = StringPrintf(
+ "interface=%s\n"
+ "driver=nl80211\n"
+ "ctrl_interface=/data/misc/wifi/hostapd\n"
+ // ssid2 signals to hostapd that the value is not a literal value
+ // for use as a SSID. In this case, we're giving it a hex string
+ // and hostapd needs to expect that.
+ "ssid2=%s\n"
+ "channel=%d\n"
+ "ieee80211n=1\n"
+ "hw_mode=%c\n"
+ "ignore_broadcast_ssid=%d\n"
+ "wowlan_triggers=any\n"
+ "%s",
+ interface_name.c_str(),
+ ssid_as_string.c_str(),
+ channel,
+ (channel <= 14) ? 'g' : 'a',
+ (is_hidden) ? 1 : 0,
+ encryption_config.c_str());
+ return result;
+}
+
+} // namespace wifi_system
+} // namespace android