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/parseint.h> 27#include <android-base/stringprintf.h> 28#include <cutils/properties.h> 29#include <openssl/evp.h> 30#include <openssl/sha.h> 31#include <private/android_filesystem_config.h> 32 33#include "wifi_system/supplicant_manager.h" 34 35using android::base::ParseInt; 36using android::base::ReadFileToString; 37using android::base::StringPrintf; 38using android::base::WriteStringToFile; 39using std::string; 40using std::vector; 41using std::stringstream; 42 43namespace android { 44namespace wifi_system { 45namespace { 46 47const int kDefaultApChannel = 6; 48const char kHostapdServiceName[] = "hostapd"; 49const char kHostapdConfigFilePath[] = "/data/misc/wifi/hostapd.conf"; 50 51 52string GeneratePsk(const vector<uint8_t>& ssid, 53 const vector<uint8_t>& passphrase) { 54 string result; 55 unsigned char psk[SHA256_DIGEST_LENGTH]; 56 57 // Use the PKCS#5 PBKDF2 with 4096 iterations 58 if (PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(passphrase.data()), 59 passphrase.size(), 60 ssid.data(), ssid.size(), 61 4096, sizeof(psk), psk) != 1) { 62 LOG(ERROR) << "Cannot generate PSK using PKCS#5 PBKDF2"; 63 return result; 64 } 65 66 stringstream ss; 67 ss << std::hex; 68 ss << std::setfill('0'); 69 for (int j = 0; j < SHA256_DIGEST_LENGTH; j++) { 70 ss << std::setw(2) << static_cast<unsigned int>(psk[j]); 71 } 72 result = ss.str(); 73 74 return result; 75} 76 77} // namespace 78 79bool HostapdManager::StartHostapd() { 80 if (!SupplicantManager::EnsureEntropyFileExists()) { 81 LOG(WARNING) << "Wi-Fi entropy file was not created"; 82 } 83 84 if (property_set("ctl.start", kHostapdServiceName) != 0) { 85 LOG(ERROR) << "Failed to start SoftAP"; 86 return false; 87 } 88 89 LOG(DEBUG) << "SoftAP started successfully"; 90 return true; 91} 92 93bool HostapdManager::StopHostapd() { 94 LOG(DEBUG) << "Stopping the SoftAP service..."; 95 96 if (property_set("ctl.stop", kHostapdServiceName) < 0) { 97 LOG(ERROR) << "Failed to stop hostapd service!"; 98 return false; 99 } 100 101 LOG(DEBUG) << "SoftAP stopped successfully"; 102 return true; 103} 104 105bool HostapdManager::WriteHostapdConfig(const string& config) { 106 if (!WriteStringToFile(config, kHostapdConfigFilePath, 107 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 108 AID_WIFI, AID_WIFI)) { 109 int error = errno; 110 LOG(ERROR) << "Cannot write hostapd config to \"" 111 << kHostapdConfigFilePath << "\": " << strerror(error); 112 struct stat st; 113 int result = stat(kHostapdConfigFilePath, &st); 114 if (result == 0) { 115 LOG(ERROR) << "hostapd config file uid: "<< st.st_uid << ", gid: " << st.st_gid 116 << ", mode: " << st.st_mode; 117 } else { 118 LOG(ERROR) << "Error calling stat() on hostapd config file: " << strerror(errno); 119 } 120 return false; 121 } 122 return true; 123} 124 125string HostapdManager::CreateHostapdConfig( 126 const string& interface_name, 127 const vector<uint8_t> ssid, 128 bool is_hidden, 129 int channel, 130 EncryptionType encryption_type, 131 const vector<uint8_t> passphrase) { 132 string result; 133 134 if (channel < 0) { 135 channel = kDefaultApChannel; 136 } 137 138 if (ssid.size() > 32) { 139 LOG(ERROR) << "SSIDs must be <= 32 bytes long"; 140 return result; 141 } 142 143 stringstream ss; 144 ss << std::hex; 145 ss << std::setfill('0'); 146 for (uint8_t b : ssid) { 147 ss << std::setw(2) << static_cast<unsigned int>(b); 148 } 149 const string ssid_as_string = ss.str(); 150 151 string encryption_config; 152 if (encryption_type != EncryptionType::kOpen) { 153 string psk = GeneratePsk(ssid, passphrase); 154 if (psk.empty()) { 155 return result; 156 } 157 if (encryption_type == EncryptionType::kWpa) { 158 encryption_config = StringPrintf("wpa=3\n" 159 "wpa_pairwise=TKIP CCMP\n" 160 "wpa_psk=%s\n", psk.c_str()); 161 } else if (encryption_type == EncryptionType::kWpa2) { 162 encryption_config = StringPrintf("wpa=2\n" 163 "rsn_pairwise=CCMP\n" 164 "wpa_psk=%s\n", psk.c_str()); 165 } else { 166 using encryption_t = std::underlying_type<EncryptionType>::type; 167 LOG(ERROR) << "Unknown encryption type (" 168 << static_cast<encryption_t>(encryption_type) 169 << ")"; 170 return result; 171 } 172 } 173 174 result = StringPrintf( 175 "interface=%s\n" 176 "driver=nl80211\n" 177 "ctrl_interface=/data/misc/wifi/hostapd/ctrl\n" 178 // ssid2 signals to hostapd that the value is not a literal value 179 // for use as a SSID. In this case, we're giving it a hex string 180 // and hostapd needs to expect that. 181 "ssid2=%s\n" 182 "channel=%d\n" 183 "ieee80211n=1\n" 184 "hw_mode=%c\n" 185 "ignore_broadcast_ssid=%d\n" 186 "wowlan_triggers=any\n" 187 "%s", 188 interface_name.c_str(), 189 ssid_as_string.c_str(), 190 channel, 191 (channel <= 14) ? 'g' : 'a', 192 (is_hidden) ? 1 : 0, 193 encryption_config.c_str()); 194 return result; 195} 196 197} // namespace wifi_system 198} // namespace android 199