blob: 8c7de320b6d9ecfe3440b212b5e12404de10e754 [file] [log] [blame]
Christopher Wiley944db7c2016-07-14 16:40:58 -07001/*
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>
Christopher Wileyaa311942016-07-28 14:01:36 -070026#include <android-base/parseint.h>
Christopher Wiley944db7c2016-07-14 16:40:58 -070027#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
Ningyuan Wangff66f412017-03-28 17:11:23 -070033#include "wifi_system/supplicant_manager.h"
Christopher Wiley944db7c2016-07-14 16:40:58 -070034
Christopher Wileyaa311942016-07-28 14:01:36 -070035using android::base::ParseInt;
36using android::base::ReadFileToString;
Daisuke Niwadc24ed72017-09-15 18:40:20 +090037using android::base::RemoveFileIfExists;
Christopher Wiley944db7c2016-07-14 16:40:58 -070038using android::base::StringPrintf;
39using android::base::WriteStringToFile;
40using std::string;
41using std::vector;
42using std::stringstream;
43
44namespace android {
45namespace wifi_system {
46namespace {
47
48const int kDefaultApChannel = 6;
49const char kHostapdServiceName[] = "hostapd";
50const char kHostapdConfigFilePath[] = "/data/misc/wifi/hostapd.conf";
Christopher Wileyaa311942016-07-28 14:01:36 -070051
Christopher Wiley944db7c2016-07-14 16:40:58 -070052
53string GeneratePsk(const vector<uint8_t>& ssid,
54 const vector<uint8_t>& passphrase) {
55 string result;
56 unsigned char psk[SHA256_DIGEST_LENGTH];
57
58 // Use the PKCS#5 PBKDF2 with 4096 iterations
59 if (PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(passphrase.data()),
60 passphrase.size(),
61 ssid.data(), ssid.size(),
62 4096, sizeof(psk), psk) != 1) {
63 LOG(ERROR) << "Cannot generate PSK using PKCS#5 PBKDF2";
64 return result;
65 }
66
67 stringstream ss;
68 ss << std::hex;
69 ss << std::setfill('0');
70 for (int j = 0; j < SHA256_DIGEST_LENGTH; j++) {
71 ss << std::setw(2) << static_cast<unsigned int>(psk[j]);
72 }
73 result = ss.str();
74
75 return result;
76}
77
78} // namespace
79
80bool HostapdManager::StartHostapd() {
Christopher Wiley944db7c2016-07-14 16:40:58 -070081 if (property_set("ctl.start", kHostapdServiceName) != 0) {
82 LOG(ERROR) << "Failed to start SoftAP";
83 return false;
84 }
85
86 LOG(DEBUG) << "SoftAP started successfully";
Christopher Wiley944db7c2016-07-14 16:40:58 -070087 return true;
88}
89
Christopher Wiley944db7c2016-07-14 16:40:58 -070090bool HostapdManager::StopHostapd() {
Christopher Wiley944db7c2016-07-14 16:40:58 -070091 LOG(DEBUG) << "Stopping the SoftAP service...";
92
93 if (property_set("ctl.stop", kHostapdServiceName) < 0) {
94 LOG(ERROR) << "Failed to stop hostapd service!";
95 return false;
96 }
97
98 LOG(DEBUG) << "SoftAP stopped successfully";
Christopher Wiley944db7c2016-07-14 16:40:58 -070099 return true;
100}
101
102bool HostapdManager::WriteHostapdConfig(const string& config) {
Daisuke Niwadc24ed72017-09-15 18:40:20 +0900103 // Remove hostapd.conf because its file owner might be system
104 // in previous OS and chmod fails in that case.
105 RemoveFileIfExists(kHostapdConfigFilePath);
Christopher Wiley944db7c2016-07-14 16:40:58 -0700106 if (!WriteStringToFile(config, kHostapdConfigFilePath,
107 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
Christopher Wiley1d3a41b2016-08-22 10:23:22 -0700108 AID_WIFI, AID_WIFI)) {
Christopher Wiley944db7c2016-07-14 16:40:58 -0700109 int error = errno;
110 LOG(ERROR) << "Cannot write hostapd config to \""
111 << kHostapdConfigFilePath << "\": " << strerror(error);
Ningyuan Wang36eb6452017-06-08 13:31:37 -0700112 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 }
Christopher Wiley944db7c2016-07-14 16:40:58 -0700120 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"
Christopher Wiley79c72002016-07-22 14:36:06 -0700177 "ctrl_interface=/data/misc/wifi/hostapd/ctrl\n"
Christopher Wiley944db7c2016-07-14 16:40:58 -0700178 // 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