hostapd_manager.cpp revision 79c7200789531ad044999a0de7ba9557c8f4c293
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "wifi_system/hostapd_manager.h" 18 19#include <iomanip> 20#include <sstream> 21#include <string> 22#include <vector> 23 24#include <android-base/file.h> 25#include <android-base/logging.h> 26#include <android-base/stringprintf.h> 27#include <cutils/properties.h> 28#include <openssl/evp.h> 29#include <openssl/sha.h> 30#include <private/android_filesystem_config.h> 31 32#include "wifi_system/wifi.h" 33 34using android::base::StringPrintf; 35using android::base::WriteStringToFile; 36using std::string; 37using std::vector; 38using std::stringstream; 39 40namespace android { 41namespace wifi_system { 42namespace { 43 44const int kDefaultApChannel = 6; 45const char kHostapdServiceName[] = "hostapd"; 46const char kHostapdConfigFilePath[] = "/data/misc/wifi/hostapd.conf"; 47 48string GeneratePsk(const vector<uint8_t>& ssid, 49 const vector<uint8_t>& passphrase) { 50 string result; 51 unsigned char psk[SHA256_DIGEST_LENGTH]; 52 53 // Use the PKCS#5 PBKDF2 with 4096 iterations 54 if (PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(passphrase.data()), 55 passphrase.size(), 56 ssid.data(), ssid.size(), 57 4096, sizeof(psk), psk) != 1) { 58 LOG(ERROR) << "Cannot generate PSK using PKCS#5 PBKDF2"; 59 return result; 60 } 61 62 stringstream ss; 63 ss << std::hex; 64 ss << std::setfill('0'); 65 for (int j = 0; j < SHA256_DIGEST_LENGTH; j++) { 66 ss << std::setw(2) << static_cast<unsigned int>(psk[j]); 67 } 68 result = ss.str(); 69 70 return result; 71} 72 73} // namespace 74 75bool HostapdManager::StartHostapd() { 76 if (hostapd_is_running_) { 77 LOG(ERROR) << "SoftAP is already running"; 78 return false; 79 } 80 81 if (ensure_entropy_file_exists() < 0) { 82 LOG(WARNING) << "Wi-Fi entropy file was not created"; 83 } 84 85 if (property_set("ctl.start", kHostapdServiceName) != 0) { 86 LOG(ERROR) << "Failed to start SoftAP"; 87 return false; 88 } 89 90 LOG(DEBUG) << "SoftAP started successfully"; 91 hostapd_is_running_ = true; 92 return true; 93} 94 95bool HostapdManager::IsHostapdRunning() { 96 return hostapd_is_running_; 97} 98 99bool HostapdManager::StopHostapd() { 100 if (!hostapd_is_running_) { 101 LOG(DEBUG) << "SoftAP is not running"; 102 return true; // Not really an error, hostapd is already stopped. 103 } 104 105 LOG(DEBUG) << "Stopping the SoftAP service..."; 106 107 if (property_set("ctl.stop", kHostapdServiceName) < 0) { 108 LOG(ERROR) << "Failed to stop hostapd service!"; 109 return false; 110 } 111 112 LOG(DEBUG) << "SoftAP stopped successfully"; 113 hostapd_is_running_ = false; 114 return true; 115} 116 117bool HostapdManager::WriteHostapdConfig(const string& config) { 118 if (!WriteStringToFile(config, kHostapdConfigFilePath, 119 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 120 AID_SYSTEM, AID_WIFI)) { 121 int error = errno; 122 LOG(ERROR) << "Cannot write hostapd config to \"" 123 << kHostapdConfigFilePath << "\": " << strerror(error); 124 return false; 125 } 126 return true; 127} 128 129string HostapdManager::CreateHostapdConfig( 130 const string& interface_name, 131 const vector<uint8_t> ssid, 132 bool is_hidden, 133 int channel, 134 EncryptionType encryption_type, 135 const vector<uint8_t> passphrase) { 136 string result; 137 138 if (channel < 0) { 139 channel = kDefaultApChannel; 140 } 141 142 if (ssid.size() > 32) { 143 LOG(ERROR) << "SSIDs must be <= 32 bytes long"; 144 return result; 145 } 146 147 stringstream ss; 148 ss << std::hex; 149 ss << std::setfill('0'); 150 for (uint8_t b : ssid) { 151 ss << std::setw(2) << static_cast<unsigned int>(b); 152 } 153 const string ssid_as_string = ss.str(); 154 155 string encryption_config; 156 if (encryption_type != EncryptionType::kOpen) { 157 string psk = GeneratePsk(ssid, passphrase); 158 if (psk.empty()) { 159 return result; 160 } 161 if (encryption_type == EncryptionType::kWpa) { 162 encryption_config = StringPrintf("wpa=3\n" 163 "wpa_pairwise=TKIP CCMP\n" 164 "wpa_psk=%s\n", psk.c_str()); 165 } else if (encryption_type == EncryptionType::kWpa2) { 166 encryption_config = StringPrintf("wpa=2\n" 167 "rsn_pairwise=CCMP\n" 168 "wpa_psk=%s\n", psk.c_str()); 169 } else { 170 using encryption_t = std::underlying_type<EncryptionType>::type; 171 LOG(ERROR) << "Unknown encryption type (" 172 << static_cast<encryption_t>(encryption_type) 173 << ")"; 174 return result; 175 } 176 } 177 178 result = StringPrintf( 179 "interface=%s\n" 180 "driver=nl80211\n" 181 "ctrl_interface=/data/misc/wifi/hostapd/ctrl\n" 182 // ssid2 signals to hostapd that the value is not a literal value 183 // for use as a SSID. In this case, we're giving it a hex string 184 // and hostapd needs to expect that. 185 "ssid2=%s\n" 186 "channel=%d\n" 187 "ieee80211n=1\n" 188 "hw_mode=%c\n" 189 "ignore_broadcast_ssid=%d\n" 190 "wowlan_triggers=any\n" 191 "%s", 192 interface_name.c_str(), 193 ssid_as_string.c_str(), 194 channel, 195 (channel <= 14) ? 'g' : 'a', 196 (is_hidden) ? 1 : 0, 197 encryption_config.c_str()); 198 return result; 199} 200 201} // namespace wifi_system 202} // namespace android 203