1 /*
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  */
9 #include <iomanip>
10 #include <sstream>
11 #include <string>
12 #include <vector>
13 
14 #include <android-base/file.h>
15 #include <android-base/stringprintf.h>
16 
17 #include "hostapd.h"
18 #include "hidl_return_util.h"
19 
20 extern "C"
21 {
22 #include "utils/eloop.h"
23 }
24 
25 // The HIDL implementation for hostapd creates a hostapd.conf dynamically for
26 // each interface. This file can then be used to hook onto the normal config
27 // file parsing logic in hostapd code.  Helps us to avoid duplication of code
28 // in the HIDL interface.
29 // TOOD(b/71872409): Add unit tests for this.
30 namespace {
31 constexpr char kConfFileNameFmt[] = "/data/vendor/wifi/hostapd/hostapd_%s.conf";
32 
33 using android::base::RemoveFileIfExists;
34 using android::base::StringPrintf;
35 using android::base::WriteStringToFile;
36 using android::hardware::wifi::hostapd::V1_1::IHostapd;
37 
WriteHostapdConfig(const std::string & interface_name,const std::string & config)38 std::string WriteHostapdConfig(
39     const std::string& interface_name, const std::string& config)
40 {
41 	const std::string file_path =
42 	    StringPrintf(kConfFileNameFmt, interface_name.c_str());
43 	if (WriteStringToFile(
44 		config, file_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
45 		getuid(), getgid())) {
46 		return file_path;
47 	}
48 	// Diagnose failure
49 	int error = errno;
50 	wpa_printf(
51 	    MSG_ERROR, "Cannot write hostapd config to %s, error: %s",
52 	    file_path.c_str(), strerror(error));
53 	struct stat st;
54 	int result = stat(file_path.c_str(), &st);
55 	if (result == 0) {
56 		wpa_printf(
57 		    MSG_ERROR, "hostapd config file uid: %d, gid: %d, mode: %d",
58 		    st.st_uid, st.st_gid, st.st_mode);
59 	} else {
60 		wpa_printf(
61 		    MSG_ERROR,
62 		    "Error calling stat() on hostapd config file: %s",
63 		    strerror(errno));
64 	}
65 	return "";
66 }
67 
CreateHostapdConfig(const IHostapd::IfaceParams & iface_params,const IHostapd::NetworkParams & nw_params)68 std::string CreateHostapdConfig(
69     const IHostapd::IfaceParams& iface_params,
70     const IHostapd::NetworkParams& nw_params)
71 {
72 	if (nw_params.ssid.size() >
73 	    static_cast<uint32_t>(
74 		IHostapd::ParamSizeLimits::SSID_MAX_LEN_IN_BYTES)) {
75 		wpa_printf(
76 		    MSG_ERROR, "Invalid SSID size: %zu", nw_params.ssid.size());
77 		return "";
78 	}
79 	if ((nw_params.encryptionType != IHostapd::EncryptionType::NONE) &&
80 	    (nw_params.pskPassphrase.size() <
81 		 static_cast<uint32_t>(
82 		     IHostapd::ParamSizeLimits::
83 			 WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES) ||
84 	     nw_params.pskPassphrase.size() >
85 		 static_cast<uint32_t>(
86 		     IHostapd::ParamSizeLimits::
87 			 WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
88 		wpa_printf(
89 		    MSG_ERROR, "Invalid psk passphrase size: %zu",
90 		    nw_params.pskPassphrase.size());
91 		return "";
92 	}
93 
94 	// SSID string
95 	std::stringstream ss;
96 	ss << std::hex;
97 	ss << std::setfill('0');
98 	for (uint8_t b : nw_params.ssid) {
99 		ss << std::setw(2) << static_cast<unsigned int>(b);
100 	}
101 	const std::string ssid_as_string = ss.str();
102 
103 	// Encryption config string
104 	std::string encryption_config_as_string;
105 	switch (nw_params.encryptionType) {
106 	case IHostapd::EncryptionType::NONE:
107 		// no security params
108 		break;
109 	case IHostapd::EncryptionType::WPA:
110 		encryption_config_as_string = StringPrintf(
111 		    "wpa=3\n"
112 		    "wpa_pairwise=TKIP CCMP\n"
113 		    "wpa_passphrase=%s",
114 		    nw_params.pskPassphrase.c_str());
115 		break;
116 	case IHostapd::EncryptionType::WPA2:
117 		encryption_config_as_string = StringPrintf(
118 		    "wpa=2\n"
119 		    "rsn_pairwise=CCMP\n"
120 		    "wpa_passphrase=%s",
121 		    nw_params.pskPassphrase.c_str());
122 		break;
123 	default:
124 		wpa_printf(MSG_ERROR, "Unknown encryption type");
125 		return "";
126 	}
127 
128 	std::string channel_config_as_string;
129 	if (iface_params.V1_0.channelParams.enableAcs) {
130 		std::string chanlist_as_string;
131 		for (const auto &range :
132 		     iface_params.channelParams.acsChannelRanges) {
133 			if (range.start != range.end) {
134 				chanlist_as_string +=
135 					StringPrintf("%d-%d ", range.start, range.end);
136 			} else {
137 				chanlist_as_string += StringPrintf("%d ", range.start);
138 			}
139 		}
140 		channel_config_as_string = StringPrintf(
141 		    "channel=0\n"
142 		    "acs_exclude_dfs=%d\n"
143 		    "chanlist=%s",
144 		    iface_params.V1_0.channelParams.acsShouldExcludeDfs,
145 		    chanlist_as_string.c_str());
146 	} else {
147 		channel_config_as_string = StringPrintf(
148 		    "channel=%d", iface_params.V1_0.channelParams.channel);
149 	}
150 
151 	// Hw Mode String
152 	std::string hw_mode_as_string;
153 	std::string ht_cap_vht_oper_chwidth_as_string;
154 	switch (iface_params.V1_0.channelParams.band) {
155 	case IHostapd::Band::BAND_2_4_GHZ:
156 		hw_mode_as_string = "hw_mode=g";
157 		break;
158 	case IHostapd::Band::BAND_5_GHZ:
159 		hw_mode_as_string = "hw_mode=a";
160 		if (iface_params.V1_0.channelParams.enableAcs) {
161 			ht_cap_vht_oper_chwidth_as_string =
162 			    "ht_capab=[HT40+]\n"
163 			    "vht_oper_chwidth=1";
164 		}
165 		break;
166 	case IHostapd::Band::BAND_ANY:
167 		hw_mode_as_string = "hw_mode=any";
168 		if (iface_params.V1_0.channelParams.enableAcs) {
169 			ht_cap_vht_oper_chwidth_as_string =
170 			    "ht_capab=[HT40+]\n"
171 			    "vht_oper_chwidth=1";
172 		}
173 		break;
174 	default:
175 		wpa_printf(MSG_ERROR, "Invalid band");
176 		return "";
177 	}
178 
179 	return StringPrintf(
180 	    "interface=%s\n"
181 	    "driver=nl80211\n"
182 	    "ctrl_interface=/data/vendor/wifi/hostapd/ctrl\n"
183 	    // ssid2 signals to hostapd that the value is not a literal value
184 	    // for use as a SSID.  In this case, we're giving it a hex
185 	    // std::string and hostapd needs to expect that.
186 	    "ssid2=%s\n"
187 	    "%s\n"
188 	    "ieee80211n=%d\n"
189 	    "ieee80211ac=%d\n"
190 	    "%s\n"
191 	    "%s\n"
192 	    "ignore_broadcast_ssid=%d\n"
193 	    "wowlan_triggers=any\n"
194 	    "%s\n",
195 	    iface_params.V1_0.ifaceName.c_str(), ssid_as_string.c_str(),
196 	    channel_config_as_string.c_str(),
197 	    iface_params.V1_0.hwModeParams.enable80211N ? 1 : 0,
198 	    iface_params.V1_0.hwModeParams.enable80211AC ? 1 : 0,
199 	    hw_mode_as_string.c_str(), ht_cap_vht_oper_chwidth_as_string.c_str(),
200 	    nw_params.isHidden ? 1 : 0, encryption_config_as_string.c_str());
201 }
202 
203 // hostapd core functions accept "C" style function pointers, so use global
204 // functions to pass to the hostapd core function and store the corresponding
205 // std::function methods to be invoked.
206 //
207 // NOTE: Using the pattern from the vendor HAL (wifi_legacy_hal.cpp).
208 //
209 // Callback to be invoked once setup is complete
210 std::function<void(struct hostapd_data*)> on_setup_complete_internal_callback;
onAsyncSetupCompleteCb(void * ctx)211 void onAsyncSetupCompleteCb(void* ctx)
212 {
213 	struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
214 	if (on_setup_complete_internal_callback) {
215 		on_setup_complete_internal_callback(iface_hapd);
216 		// Invalidate this callback since we don't want this firing
217 		// again.
218 		on_setup_complete_internal_callback = nullptr;
219 	}
220 }
221 }  // namespace
222 
223 namespace android {
224 namespace hardware {
225 namespace wifi {
226 namespace hostapd {
227 namespace V1_1 {
228 namespace implementation {
229 using hidl_return_util::call;
230 using namespace android::hardware::wifi::hostapd::V1_0;
231 
Hostapd(struct hapd_interfaces * interfaces)232 Hostapd::Hostapd(struct hapd_interfaces* interfaces) : interfaces_(interfaces)
233 {}
234 
addAccessPoint(const V1_0::IHostapd::IfaceParams & iface_params,const NetworkParams & nw_params,addAccessPoint_cb _hidl_cb)235 Return<void> Hostapd::addAccessPoint(
236     const V1_0::IHostapd::IfaceParams& iface_params,
237     const NetworkParams& nw_params, addAccessPoint_cb _hidl_cb)
238 {
239 	return call(
240 	    this, &Hostapd::addAccessPointInternal, _hidl_cb, iface_params,
241 	    nw_params);
242 }
243 
addAccessPoint_1_1(const IfaceParams & iface_params,const NetworkParams & nw_params,addAccessPoint_cb _hidl_cb)244 Return<void> Hostapd::addAccessPoint_1_1(
245     const IfaceParams& iface_params, const NetworkParams& nw_params,
246     addAccessPoint_cb _hidl_cb)
247 {
248 	return call(
249 	    this, &Hostapd::addAccessPointInternal_1_1, _hidl_cb, iface_params,
250 	    nw_params);
251 }
252 
removeAccessPoint(const hidl_string & iface_name,removeAccessPoint_cb _hidl_cb)253 Return<void> Hostapd::removeAccessPoint(
254     const hidl_string& iface_name, removeAccessPoint_cb _hidl_cb)
255 {
256 	return call(
257 	    this, &Hostapd::removeAccessPointInternal, _hidl_cb, iface_name);
258 }
259 
terminate()260 Return<void> Hostapd::terminate()
261 {
262 	wpa_printf(MSG_INFO, "Terminating...");
263 	eloop_terminate();
264 	return Void();
265 }
266 
registerCallback(const sp<IHostapdCallback> & callback,registerCallback_cb _hidl_cb)267 Return<void> Hostapd::registerCallback(
268     const sp<IHostapdCallback>& callback, registerCallback_cb _hidl_cb)
269 {
270 	return call(
271 	    this, &Hostapd::registerCallbackInternal, _hidl_cb, callback);
272 }
273 
addAccessPointInternal(const V1_0::IHostapd::IfaceParams & iface_params,const NetworkParams & nw_params)274 HostapdStatus Hostapd::addAccessPointInternal(
275     const V1_0::IHostapd::IfaceParams& iface_params,
276     const NetworkParams& nw_params)
277 {
278 	return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
279 }
280 
addAccessPointInternal_1_1(const IfaceParams & iface_params,const NetworkParams & nw_params)281 HostapdStatus Hostapd::addAccessPointInternal_1_1(
282     const IfaceParams& iface_params, const NetworkParams& nw_params)
283 {
284 	if (hostapd_get_iface(interfaces_, iface_params.V1_0.ifaceName.c_str())) {
285 		wpa_printf(
286 		    MSG_ERROR, "Interface %s already present",
287 		    iface_params.V1_0.ifaceName.c_str());
288 		return {HostapdStatusCode::FAILURE_IFACE_EXISTS, ""};
289 	}
290 	const auto conf_params = CreateHostapdConfig(iface_params, nw_params);
291 	if (conf_params.empty()) {
292 		wpa_printf(MSG_ERROR, "Failed to create config params");
293 		return {HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
294 	}
295 	const auto conf_file_path =
296 	    WriteHostapdConfig(iface_params.V1_0.ifaceName, conf_params);
297 	if (conf_file_path.empty()) {
298 		wpa_printf(MSG_ERROR, "Failed to write config file");
299 		return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
300 	}
301 	std::string add_iface_param_str = StringPrintf(
302 	    "%s config=%s", iface_params.V1_0.ifaceName.c_str(),
303 	    conf_file_path.c_str());
304 	std::vector<char> add_iface_param_vec(
305 	    add_iface_param_str.begin(), add_iface_param_str.end() + 1);
306 	if (hostapd_add_iface(interfaces_, add_iface_param_vec.data()) < 0) {
307 		wpa_printf(
308 		    MSG_ERROR, "Adding interface %s failed",
309 		    add_iface_param_str.c_str());
310 		return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
311 	}
312 	struct hostapd_data* iface_hapd =
313 	    hostapd_get_iface(interfaces_, iface_params.V1_0.ifaceName.c_str());
314 	WPA_ASSERT(iface_hapd != nullptr && iface_hapd->iface != nullptr);
315 	// Register the setup complete callbacks
316 	on_setup_complete_internal_callback =
317 	    [this](struct hostapd_data* iface_hapd) {
318 		    wpa_printf(
319 			MSG_DEBUG, "AP interface setup completed - state %s",
320 			hostapd_state_text(iface_hapd->iface->state));
321 		    if (iface_hapd->iface->state == HAPD_IFACE_DISABLED) {
322 			    // Invoke the failure callback on all registered
323 			    // clients.
324 			    for (const auto& callback : callbacks_) {
325 				    callback->onFailure(
326 					iface_hapd->conf->iface);
327 			    }
328 		    }
329 	    };
330 	iface_hapd->setup_complete_cb = onAsyncSetupCompleteCb;
331 	iface_hapd->setup_complete_cb_ctx = iface_hapd;
332 	if (hostapd_enable_iface(iface_hapd->iface) < 0) {
333 		wpa_printf(
334 		    MSG_ERROR, "Enabling interface %s failed",
335 		    iface_params.V1_0.ifaceName.c_str());
336 		return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
337 	}
338 	return {HostapdStatusCode::SUCCESS, ""};
339 }
340 
removeAccessPointInternal(const std::string & iface_name)341 HostapdStatus Hostapd::removeAccessPointInternal(const std::string& iface_name)
342 {
343 	std::vector<char> remove_iface_param_vec(
344 	    iface_name.begin(), iface_name.end() + 1);
345 	if (hostapd_remove_iface(interfaces_, remove_iface_param_vec.data()) <
346 	    0) {
347 		wpa_printf(
348 		    MSG_ERROR, "Removing interface %s failed",
349 		    iface_name.c_str());
350 		return {HostapdStatusCode::FAILURE_UNKNOWN, ""};
351 	}
352 	return {HostapdStatusCode::SUCCESS, ""};
353 }
354 
registerCallbackInternal(const sp<IHostapdCallback> & callback)355 HostapdStatus Hostapd::registerCallbackInternal(
356     const sp<IHostapdCallback>& callback)
357 {
358 	callbacks_.push_back(callback);
359 	return {HostapdStatusCode::SUCCESS, ""};
360 }
361 
362 }  // namespace implementation
363 }  // namespace V1_1
364 }  // namespace hostapd
365 }  // namespace wifi
366 }  // namespace hardware
367 }  // namespace android
368