diff options
author | Christopher Wiley <wiley@google.com> | 2016-07-14 16:40:58 -0700 |
---|---|---|
committer | Christopher Wiley <wiley@google.com> | 2016-07-18 13:58:21 -0700 |
commit | 944db7cbdafa91279b40dd8a7737307e49cf711e (patch) | |
tree | 3b6cb1aef535ccb223437a8b27a622d14de0a0d2 /libwifi_system/hostapd_manager.cpp | |
parent | 3efd47ff5e926cc1fa042e288e129df10fa4ec83 (diff) | |
download | wifi-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.cpp | 202 |
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 |