blob: 04e284007d9444f0f37b5cd041075afe1d88a49b [file] [log] [blame]
Roshan Piuscc817562017-12-22 14:45:05 -08001/*
2 * hidl interface for wpa_hostapd daemon
3 * Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2004-2018, Roshan Pius <rpius@google.com>
5 *
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
Roshan Pius30b452e2017-12-27 13:36:21 -08009#include <iomanip>
10#include <sstream>
11#include <string>
12#include <vector>
13
14#include <android-base/file.h>
15#include <android-base/stringprintf.h>
Roshan Piuscc817562017-12-22 14:45:05 -080016
17#include "hostapd.h"
18#include "hidl_return_util.h"
19
Roshan Pius30b452e2017-12-27 13:36:21 -080020// The HIDL implementation for hostapd creates a hostapd.conf dynamically for
21// each interface. This file can then be used to hook onto the normal config
22// file parsing logic in hostapd code. Helps us to avoid duplication of code
23// in the HIDL interface.
24// TOOD(b/71872409): Add unit tests for this.
25namespace {
26constexpr char kConfFileNameFmt[] = "/data/vendor/wifi/hostapd/hostapd_%s.conf";
27
28using android::base::RemoveFileIfExists;
29using android::base::StringPrintf;
30using android::base::WriteStringToFile;
31using android::hardware::wifi::hostapd::V1_0::IHostapd;
32
33std::string WriteHostapdConfig(
34 const std::string& interface_name, const std::string& config)
35{
36 const std::string file_path =
37 StringPrintf(kConfFileNameFmt, interface_name.c_str());
38 if (WriteStringToFile(
39 config, file_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
40 getuid(), getgid())) {
41 return file_path;
42 }
43 // Diagnose failure
44 int error = errno;
45 wpa_printf(
46 MSG_ERROR, "Cannot write hostapd config to %s, error: %s",
47 file_path.c_str(), strerror(error));
48 struct stat st;
49 int result = stat(file_path.c_str(), &st);
50 if (result == 0) {
51 wpa_printf(
52 MSG_ERROR, "hostapd config file uid: %d, gid: %d, mode: %d",
53 st.st_uid, st.st_gid, st.st_mode);
54 } else {
55 wpa_printf(
56 MSG_ERROR,
57 "Error calling stat() on hostapd config file: %s",
58 strerror(errno));
59 }
60 return "";
61}
62
63std::string CreateHostapdConfig(
64 const IHostapd::IfaceParams& iface_params,
65 const IHostapd::NetworkParams& nw_params)
66{
67 if (nw_params.ssid.size() >
68 static_cast<uint32_t>(
69 IHostapd::ParamSizeLimits::SSID_MAX_LEN_IN_BYTES)) {
70 wpa_printf(
71 MSG_ERROR, "Invalid SSID size: %zu", nw_params.ssid.size());
72 return "";
73 }
Roshan Pius0b8a64f2018-01-23 11:42:34 -080074 if ((nw_params.encryptionType != IHostapd::EncryptionType::NONE) &&
75 (nw_params.pskPassphrase.size() <
76 static_cast<uint32_t>(
77 IHostapd::ParamSizeLimits::
78 WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES) ||
79 nw_params.pskPassphrase.size() >
80 static_cast<uint32_t>(
81 IHostapd::ParamSizeLimits::
82 WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
Roshan Pius30b452e2017-12-27 13:36:21 -080083 wpa_printf(
84 MSG_ERROR, "Invalid psk passphrase size: %zu",
85 nw_params.pskPassphrase.size());
86 return "";
87 }
88
89 // SSID string
90 std::stringstream ss;
91 ss << std::hex;
92 ss << std::setfill('0');
93 for (uint8_t b : nw_params.ssid) {
94 ss << std::setw(2) << static_cast<unsigned int>(b);
95 }
96 const std::string ssid_as_string = ss.str();
97
98 // Encryption config string
99 std::string encryption_config_as_string;
100 switch (nw_params.encryptionType) {
101 case IHostapd::EncryptionType::NONE:
102 // no security params
103 break;
104 case IHostapd::EncryptionType::WPA:
105 encryption_config_as_string = StringPrintf(
106 "wpa=3\n"
107 "wpa_pairwise=TKIP CCMP\n"
108 "wpa_passphrase=%s",
109 nw_params.pskPassphrase.c_str());
110 break;
111 case IHostapd::EncryptionType::WPA2:
112 encryption_config_as_string = StringPrintf(
113 "wpa=2\n"
114 "rsn_pairwise=CCMP\n"
115 "wpa_passphrase=%s",
116 nw_params.pskPassphrase.c_str());
117 break;
118 default:
119 wpa_printf(MSG_ERROR, "Unknown encryption type");
120 return "";
121 }
122
123 std::string channel_config_as_string;
124 if (iface_params.channelParams.enableAcs) {
125 channel_config_as_string = StringPrintf(
126 "channel=0\n"
127 "acs_exclude_dfs=%d",
128 iface_params.channelParams.acsShouldExcludeDfs);
129 } else {
130 channel_config_as_string = StringPrintf(
131 "channel=%d", iface_params.channelParams.channel);
132 }
133
134 // Hw Mode String
135 std::string hw_mode_as_string;
136 switch (iface_params.channelParams.band) {
137 case IHostapd::Band::BAND_2_4_GHZ:
138 hw_mode_as_string = "g";
139 break;
140 case IHostapd::Band::BAND_5_GHZ:
141 hw_mode_as_string = "a";
142 break;
143 case IHostapd::Band::BAND_ANY:
144 hw_mode_as_string = "any";
145 break;
146 default:
147 wpa_printf(MSG_ERROR, "Invalid band");
148 return "";
149 }
150
151 return StringPrintf(
152 "interface=%s\n"
153 "driver=nl80211\n"
154 // ssid2 signals to hostapd that the value is not a literal value
155 // for use as a SSID. In this case, we're giving it a hex
156 // std::string and hostapd needs to expect that.
157 "ssid2=%s\n"
158 "%s\n"
159 "ieee80211n=%d\n"
160 "ieee80211ac=%d\n"
161 "hw_mode=%s\n"
162 "ignore_broadcast_ssid=%d\n"
163 "wowlan_triggers=any\n"
164 "%s\n",
165 iface_params.ifaceName.c_str(), ssid_as_string.c_str(),
166 channel_config_as_string.c_str(),
167 iface_params.hwModeParams.enable80211N ? 1 : 0,
168 iface_params.hwModeParams.enable80211AC ? 1 : 0,
169 hw_mode_as_string.c_str(), nw_params.isHidden ? 1 : 0,
170 encryption_config_as_string.c_str());
171}
172} // namespace
173
Roshan Piuscc817562017-12-22 14:45:05 -0800174namespace android {
175namespace hardware {
176namespace wifi {
177namespace hostapd {
178namespace V1_0 {
179namespace implementation {
180using hidl_return_util::call;
181
182Hostapd::Hostapd(struct hapd_interfaces* interfaces) : interfaces_(interfaces)
183{}
184
185Return<void> Hostapd::addAccessPoint(
186 const IfaceParams& iface_params, const NetworkParams& nw_params,
187 addAccessPoint_cb _hidl_cb)
188{
189 return call(
190 this, &Hostapd::addAccessPointInternal, _hidl_cb, iface_params,
191 nw_params);
192}
193
194Return<void> Hostapd::removeAccessPoint(
195 const hidl_string& iface_name, removeAccessPoint_cb _hidl_cb)
196{
197 return call(
198 this, &Hostapd::removeAccessPointInternal, _hidl_cb, iface_name);
199}
200
201HostapdStatus Hostapd::addAccessPointInternal(
202 const IfaceParams& iface_params, const NetworkParams& nw_params)
203{
Roshan Pius087d8692017-12-27 14:11:44 -0800204 if (hostapd_get_iface(interfaces_, iface_params.ifaceName.c_str())) {
205 wpa_printf(
206 MSG_ERROR, "Interface %s already present",
207 iface_params.ifaceName.c_str());
208 return {HostapdStatusCode::FAILURE_IFACE_EXISTS, ""};
209 }
210 const auto conf_params = CreateHostapdConfig(iface_params, nw_params);
211 if (conf_params.empty()) {
212 wpa_printf(MSG_ERROR, "Failed to create config params");
213 return {HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
214 }
215 const auto conf_file_path =
216 WriteHostapdConfig(iface_params.ifaceName, conf_params);
217 if (conf_file_path.empty()) {
218 wpa_printf(MSG_ERROR, "Failed to write config file");
219 return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
220 }
221 std::string add_iface_param_str = StringPrintf(
222 "%s config=%s", iface_params.ifaceName.c_str(),
223 conf_file_path.c_str());
224 std::vector<char> add_iface_param_vec(
225 add_iface_param_str.begin(), add_iface_param_str.end() + 1);
226 if (hostapd_add_iface(interfaces_, add_iface_param_vec.data()) < 0) {
227 wpa_printf(
228 MSG_ERROR, "Adding interface %s failed",
229 add_iface_param_str.c_str());
230 return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
231 }
232 struct hostapd_data* iface_hapd =
233 hostapd_get_iface(interfaces_, iface_params.ifaceName.c_str());
234 WPA_ASSERT(iface_hapd != nullptr && iface_hapd->iface != nullptr);
235 if (hostapd_enable_iface(iface_hapd->iface) < 0) {
236 wpa_printf(
237 MSG_ERROR, "Enabling interface %s failed",
238 iface_params.ifaceName.c_str());
239 return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
240 }
Roshan Piuscc817562017-12-22 14:45:05 -0800241 return {HostapdStatusCode::SUCCESS, ""};
242}
243
244HostapdStatus Hostapd::removeAccessPointInternal(const std::string& iface_name)
245{
Roshan Pius087d8692017-12-27 14:11:44 -0800246 std::vector<char> remove_iface_param_vec(
247 iface_name.begin(), iface_name.end() + 1);
248 if (hostapd_remove_iface(interfaces_, remove_iface_param_vec.data()) <
249 0) {
250 wpa_printf(
251 MSG_ERROR, "Removing interface %s failed",
252 iface_name.c_str());
253 return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
254 }
Roshan Piuscc817562017-12-22 14:45:05 -0800255 return {HostapdStatusCode::SUCCESS, ""};
256}
257} // namespace implementation
258} // namespace V1_0
259} // namespace hostapd
260} // namespace wifi
261} // namespace hardware
262} // namespace android