1/*
2 * hidl interface for wpa_supplicant daemon
3 * Copyright (c) 2004-2016, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2004-2016, 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
10#include "hidl_manager.h"
11#include "hidl_return_util.h"
12#include "supplicant.h"
13
14#include <android-base/file.h>
15#include <fcntl.h>
16#include <sys/stat.h>
17
18namespace {
19// Pre-populated interface params for interfaces controlled by wpa_supplicant.
20// Note: This may differ for other OEM's. So, modify this accordingly.
21constexpr char kIfaceDriverName[] = "nl80211";
22constexpr char kStaIfaceConfPath[] =
23    "/data/vendor/wifi/wpa/wpa_supplicant.conf";
24constexpr char kStaIfaceConfOverlayPath[] =
25    "/vendor/etc/wifi/wpa_supplicant_overlay.conf";
26constexpr char kP2pIfaceConfPath[] =
27    "/data/vendor/wifi/wpa/p2p_supplicant.conf";
28constexpr char kP2pIfaceConfOverlayPath[] =
29    "/vendor/etc/wifi/p2p_supplicant_overlay.conf";
30// Migrate conf files for existing devices.
31constexpr char kSystemTemplateConfPath[] =
32    "/system/etc/wifi/wpa_supplicant.conf";
33constexpr char kVendorTemplateConfPath[] =
34    "/vendor/etc/wifi/wpa_supplicant.conf";
35constexpr char kOldStaIfaceConfPath[] =
36    "/data/misc/wifi/wpa_supplicant.conf";
37constexpr char kOldP2pIfaceConfPath[] =
38    "/data/misc/wifi/p2p_supplicant.conf";
39constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
40
41int copyFile(
42    const std::string& src_file_path, const std::string& dest_file_path)
43{
44	std::string file_contents;
45	if (!android::base::ReadFileToString(src_file_path, &file_contents)) {
46		wpa_printf(
47		    MSG_ERROR, "Failed to read from %s. Errno: %s",
48		    src_file_path.c_str(), strerror(errno));
49		return -1;
50	}
51	if (!android::base::WriteStringToFile(
52		file_contents, dest_file_path, kConfigFileMode, getuid(),
53		getgid())) {
54		wpa_printf(
55		    MSG_ERROR, "Failed to write to %s. Errno: %s",
56		    dest_file_path.c_str(), strerror(errno));
57		return -1;
58	}
59	return 0;
60}
61
62/**
63 * Copy |src_file_path| to |dest_file_path| if it exists.
64 *
65 * Returns 1 if |src_file_path| does not exist or not accessible,
66 * Returns -1 if the copy fails.
67 * Returns 0 if the copy succeeds.
68 */
69int copyFileIfItExists(
70    const std::string& src_file_path, const std::string& dest_file_path)
71{
72	int ret = access(src_file_path.c_str(), R_OK);
73	// Sepolicy denial (2018+ device) will return EACCESS instead of ENOENT.
74	if ((ret != 0) && ((errno == ENOENT) || (errno == EACCES))) {
75		return 1;
76	}
77	ret = copyFile(src_file_path, dest_file_path);
78	if (ret != 0) {
79		wpa_printf(
80		    MSG_ERROR, "Failed copying %s to %s.",
81		    src_file_path.c_str(), dest_file_path.c_str());
82		return -1;
83	}
84	return 0;
85}
86
87/**
88 * Ensure that the specified config file pointed by |config_file_path| exists.
89 * a) If the |config_file_path| exists with the correct permissions, return.
90 * b) If the |config_file_path| does not exist, but |old_config_file_path|
91 * exists, copy over the contents of the |old_config_file_path| to
92 * |config_file_path|.
93 * c) If the |config_file_path| & |old_config_file_path|
94 * does not exists, copy over the contents of |template_config_file_path|.
95 */
96int ensureConfigFileExists(
97    const std::string& config_file_path,
98    const std::string& old_config_file_path)
99{
100	int ret = access(config_file_path.c_str(), R_OK | W_OK);
101	if (ret == 0) {
102		return 0;
103	}
104	if (errno == EACCES) {
105		ret = chmod(config_file_path.c_str(), kConfigFileMode);
106		if (ret == 0) {
107			return 0;
108		} else {
109			wpa_printf(
110			    MSG_ERROR, "Cannot set RW to %s. Errno: %s",
111			    config_file_path.c_str(), strerror(errno));
112			return -1;
113		}
114	} else if (errno != ENOENT) {
115		wpa_printf(
116		    MSG_ERROR, "Cannot acces %s. Errno: %s",
117		    config_file_path.c_str(), strerror(errno));
118		return -1;
119	}
120	ret = copyFileIfItExists(old_config_file_path, config_file_path);
121	if (ret == 0) {
122		wpa_printf(
123		    MSG_INFO, "Migrated conf file from %s to %s",
124		    old_config_file_path.c_str(), config_file_path.c_str());
125		unlink(old_config_file_path.c_str());
126		return 0;
127	} else if (ret == -1) {
128		unlink(config_file_path.c_str());
129		return -1;
130	}
131	ret = copyFileIfItExists(kVendorTemplateConfPath, config_file_path);
132	if (ret == 0) {
133		wpa_printf(
134		    MSG_INFO, "Copied template conf file from %s to %s",
135		    kVendorTemplateConfPath, config_file_path.c_str());
136		return 0;
137	} else if (ret == -1) {
138		unlink(config_file_path.c_str());
139		return -1;
140	}
141	ret = copyFileIfItExists(kSystemTemplateConfPath, config_file_path);
142	if (ret == 0) {
143		wpa_printf(
144		    MSG_INFO, "Copied template conf file from %s to %s",
145		    kSystemTemplateConfPath, config_file_path.c_str());
146		return 0;
147	} else if (ret == -1) {
148		unlink(config_file_path.c_str());
149		return -1;
150	}
151	// Did not create the conf file.
152	return -1;
153}
154}  // namespace
155
156namespace android {
157namespace hardware {
158namespace wifi {
159namespace supplicant {
160namespace V1_1 {
161namespace implementation {
162using hidl_return_util::validateAndCall;
163
164Supplicant::Supplicant(struct wpa_global* global) : wpa_global_(global) {}
165bool Supplicant::isValid()
166{
167	// This top level object cannot be invalidated.
168	return true;
169}
170
171Return<void> Supplicant::addInterface(
172    const IfaceInfo& iface_info, addInterface_cb _hidl_cb)
173{
174	return validateAndCall(
175	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
176	    &Supplicant::addInterfaceInternal, _hidl_cb, iface_info);
177}
178
179Return<void> Supplicant::removeInterface(
180    const IfaceInfo& iface_info, removeInterface_cb _hidl_cb)
181{
182	return validateAndCall(
183	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
184	    &Supplicant::removeInterfaceInternal, _hidl_cb, iface_info);
185}
186
187Return<void> Supplicant::getInterface(
188    const IfaceInfo& iface_info, getInterface_cb _hidl_cb)
189{
190	return validateAndCall(
191	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
192	    &Supplicant::getInterfaceInternal, _hidl_cb, iface_info);
193}
194
195Return<void> Supplicant::listInterfaces(listInterfaces_cb _hidl_cb)
196{
197	return validateAndCall(
198	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
199	    &Supplicant::listInterfacesInternal, _hidl_cb);
200}
201
202Return<void> Supplicant::registerCallback(
203    const sp<ISupplicantCallback>& callback, registerCallback_cb _hidl_cb)
204{
205	return validateAndCall(
206	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
207	    &Supplicant::registerCallbackInternal, _hidl_cb, callback);
208}
209
210Return<void> Supplicant::setDebugParams(
211    ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys,
212    setDebugParams_cb _hidl_cb)
213{
214	return validateAndCall(
215	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
216	    &Supplicant::setDebugParamsInternal, _hidl_cb, level,
217	    show_timestamp, show_keys);
218}
219
220Return<void> Supplicant::setConcurrencyPriority(
221    IfaceType type, setConcurrencyPriority_cb _hidl_cb)
222{
223	return validateAndCall(
224	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
225	    &Supplicant::setConcurrencyPriorityInternal, _hidl_cb, type);
226}
227
228Return<ISupplicant::DebugLevel> Supplicant::getDebugLevel()
229{
230	// TODO: Add SupplicantStatus in this method return for uniformity with
231	// the other methods in supplicant HIDL interface.
232	return (ISupplicant::DebugLevel)wpa_debug_level;
233}
234
235Return<bool> Supplicant::isDebugShowTimestampEnabled()
236{
237	// TODO: Add SupplicantStatus in this method return for uniformity with
238	// the other methods in supplicant HIDL interface.
239	return ((wpa_debug_timestamp != 0) ? true : false);
240}
241
242Return<bool> Supplicant::isDebugShowKeysEnabled()
243{
244	// TODO: Add SupplicantStatus in this method return for uniformity with
245	// the other methods in supplicant HIDL interface.
246	return ((wpa_debug_show_keys != 0) ? true : false);
247}
248
249Return<void> Supplicant::terminate()
250{
251	wpa_printf(MSG_INFO, "Terminating...");
252	wpa_supplicant_terminate_proc(wpa_global_);
253	return Void();
254}
255
256std::pair<SupplicantStatus, sp<ISupplicantIface>>
257Supplicant::addInterfaceInternal(const IfaceInfo& iface_info)
258{
259	android::sp<ISupplicantIface> iface;
260
261	// Check if required |ifname| argument is empty.
262	if (iface_info.name.empty()) {
263		return {{SupplicantStatusCode::FAILURE_ARGS_INVALID, ""}, {}};
264	}
265	// Try to get the wpa_supplicant record for this iface, return
266	// the iface object with the appropriate status code if it exists.
267	SupplicantStatus status;
268	std::tie(status, iface) = getInterfaceInternal(iface_info);
269	if (status.code == SupplicantStatusCode::SUCCESS) {
270		return {{SupplicantStatusCode::FAILURE_IFACE_EXISTS, ""},
271			iface};
272	}
273
274	struct wpa_interface iface_params = {};
275	iface_params.driver = kIfaceDriverName;
276	if (iface_info.type == IfaceType::P2P) {
277		if (ensureConfigFileExists(
278			kP2pIfaceConfPath, kOldP2pIfaceConfPath) != 0) {
279			wpa_printf(
280			    MSG_ERROR, "Conf file does not exists: %s",
281			    kP2pIfaceConfPath);
282			return {{SupplicantStatusCode::FAILURE_UNKNOWN,
283				 "Conf file does not exist"},
284				{}};
285		}
286		iface_params.confname = kP2pIfaceConfPath;
287		int ret = access(kP2pIfaceConfOverlayPath, R_OK);
288		if (ret == 0) {
289			iface_params.confanother = kP2pIfaceConfOverlayPath;
290		}
291	} else {
292		if (ensureConfigFileExists(
293			kStaIfaceConfPath, kOldStaIfaceConfPath) != 0) {
294			wpa_printf(
295			    MSG_ERROR, "Conf file does not exists: %s",
296			    kStaIfaceConfPath);
297			return {{SupplicantStatusCode::FAILURE_UNKNOWN,
298				 "Conf file does not exist"},
299				{}};
300		}
301		iface_params.confname = kStaIfaceConfPath;
302		int ret = access(kStaIfaceConfOverlayPath, R_OK);
303		if (ret == 0) {
304			iface_params.confanother = kStaIfaceConfOverlayPath;
305		}
306	}
307	iface_params.ifname = iface_info.name.c_str();
308	struct wpa_supplicant* wpa_s =
309	    wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL);
310	if (!wpa_s) {
311		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
312	}
313	// The supplicant core creates a corresponding hidl object via
314	// HidlManager when |wpa_supplicant_add_iface| is called.
315	return getInterfaceInternal(iface_info);
316}
317
318SupplicantStatus Supplicant::removeInterfaceInternal(
319    const IfaceInfo& iface_info)
320{
321	struct wpa_supplicant* wpa_s =
322	    wpa_supplicant_get_iface(wpa_global_, iface_info.name.c_str());
323	if (!wpa_s) {
324		return {SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""};
325	}
326	if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0)) {
327		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
328	}
329	return {SupplicantStatusCode::SUCCESS, ""};
330}
331
332std::pair<SupplicantStatus, sp<ISupplicantIface>>
333Supplicant::getInterfaceInternal(const IfaceInfo& iface_info)
334{
335	struct wpa_supplicant* wpa_s =
336	    wpa_supplicant_get_iface(wpa_global_, iface_info.name.c_str());
337	if (!wpa_s) {
338		return {{SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""},
339			nullptr};
340	}
341	HidlManager* hidl_manager = HidlManager::getInstance();
342	if (iface_info.type == IfaceType::P2P) {
343		android::sp<ISupplicantP2pIface> iface;
344		if (!hidl_manager ||
345		    hidl_manager->getP2pIfaceHidlObjectByIfname(
346			wpa_s->ifname, &iface)) {
347			return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
348				iface};
349		}
350		// Set this flag true here, since there is no HIDL initialize method for the p2p
351		// config, and the supplicant interface is not ready when the p2p iface is created.
352		wpa_s->conf->persistent_reconnect = true;
353		return {{SupplicantStatusCode::SUCCESS, ""}, iface};
354	} else {
355		android::sp<ISupplicantStaIface> iface;
356		if (!hidl_manager ||
357		    hidl_manager->getStaIfaceHidlObjectByIfname(
358			wpa_s->ifname, &iface)) {
359			return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""},
360				iface};
361		}
362		return {{SupplicantStatusCode::SUCCESS, ""}, iface};
363	}
364}
365
366std::pair<SupplicantStatus, std::vector<ISupplicant::IfaceInfo>>
367Supplicant::listInterfacesInternal()
368{
369	std::vector<ISupplicant::IfaceInfo> ifaces;
370	for (struct wpa_supplicant* wpa_s = wpa_global_->ifaces; wpa_s;
371	     wpa_s = wpa_s->next) {
372		if (wpa_s->global->p2p_init_wpa_s == wpa_s) {
373			ifaces.emplace_back(ISupplicant::IfaceInfo{
374			    IfaceType::P2P, wpa_s->ifname});
375		} else {
376			ifaces.emplace_back(ISupplicant::IfaceInfo{
377			    IfaceType::STA, wpa_s->ifname});
378		}
379	}
380	return {{SupplicantStatusCode::SUCCESS, ""}, std::move(ifaces)};
381}
382
383SupplicantStatus Supplicant::registerCallbackInternal(
384    const sp<ISupplicantCallback>& callback)
385{
386	HidlManager* hidl_manager = HidlManager::getInstance();
387	if (!hidl_manager ||
388	    hidl_manager->addSupplicantCallbackHidlObject(callback)) {
389		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
390	}
391	return {SupplicantStatusCode::SUCCESS, ""};
392}
393
394SupplicantStatus Supplicant::setDebugParamsInternal(
395    ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys)
396{
397	if (wpa_supplicant_set_debug_params(
398		wpa_global_, static_cast<uint32_t>(level), show_timestamp,
399		show_keys)) {
400		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
401	}
402	return {SupplicantStatusCode::SUCCESS, ""};
403}
404
405SupplicantStatus Supplicant::setConcurrencyPriorityInternal(IfaceType type)
406{
407	if (type == IfaceType::STA) {
408		wpa_global_->conc_pref =
409		    wpa_global::wpa_conc_pref::WPA_CONC_PREF_STA;
410	} else if (type == IfaceType::P2P) {
411		wpa_global_->conc_pref =
412		    wpa_global::wpa_conc_pref::WPA_CONC_PREF_P2P;
413	} else {
414		return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""};
415	}
416	return SupplicantStatus{SupplicantStatusCode::SUCCESS, ""};
417}
418}  // namespace implementation
419}  // namespace V1_1
420}  // namespace wifi
421}  // namespace supplicant
422}  // namespace hardware
423}  // namespace android
424