blob: ee6f8097769172e605864268e229faadb70e59a4 [file] [log] [blame]
Gabriel Biren57ededa2021-09-03 16:08:50 +00001/*
2 * WPA Supplicant - Supplicant Aidl interface
3 * Copyright (c) 2021, Google Inc. All rights reserved.
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "aidl_manager.h"
10#include "aidl_return_util.h"
11#include "misc_utils.h"
12#include "supplicant.h"
13#include "p2p_iface.h"
14
15#include <android-base/file.h>
16#include <fcntl.h>
17#include <sys/stat.h>
18
19namespace {
20
21// Pre-populated interface params for interfaces controlled by wpa_supplicant.
22// Note: This may differ for other OEM's. So, modify this accordingly.
23constexpr char kIfaceDriverName[] = "nl80211";
24constexpr char kStaIfaceConfPath[] =
25 "/data/vendor/wifi/wpa/wpa_supplicant.conf";
26static const char* kStaIfaceConfOverlayPaths[] = {
27 "/apex/com.android.wifi.hal/etc/wifi/wpa_supplicant_overlay.conf",
28 "/vendor/etc/wifi/wpa_supplicant_overlay.conf",
29};
30constexpr char kP2pIfaceConfPath[] =
31 "/data/vendor/wifi/wpa/p2p_supplicant.conf";
32static const char* kP2pIfaceConfOverlayPaths[] = {
33 "/apex/com.android.wifi.hal/etc/wifi/p2p_supplicant_overlay.conf",
34 "/vendor/etc/wifi/p2p_supplicant_overlay.conf",
35};
36// Migrate conf files for existing devices.
37static const char* kTemplateConfPaths[] = {
38 "/apex/com.android.wifi.hal/etc/wifi/wpa_supplicant.conf",
39 "/vendor/etc/wifi/wpa_supplicant.conf",
40 "/system/etc/wifi/wpa_supplicant.conf",
41};
42constexpr char kOldStaIfaceConfPath[] = "/data/misc/wifi/wpa_supplicant.conf";
43constexpr char kOldP2pIfaceConfPath[] = "/data/misc/wifi/p2p_supplicant.conf";
44constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
45
46const char* resolvePath(const char* paths[], size_t size)
47{
48 for (int i = 0; i < size; ++i) {
49 if (access(paths[i], R_OK) == 0) {
50 return paths[i];
51 }
52 }
53 return nullptr;
54}
55
56int copyFile(
57 const std::string& src_file_path, const std::string& dest_file_path)
58{
59 std::string file_contents;
60 if (!android::base::ReadFileToString(src_file_path, &file_contents)) {
61 wpa_printf(
62 MSG_ERROR, "Failed to read from %s. Errno: %s",
63 src_file_path.c_str(), strerror(errno));
64 return -1;
65 }
66 if (!android::base::WriteStringToFile(
67 file_contents, dest_file_path, kConfigFileMode, getuid(),
68 getgid())) {
69 wpa_printf(
70 MSG_ERROR, "Failed to write to %s. Errno: %s",
71 dest_file_path.c_str(), strerror(errno));
72 return -1;
73 }
74 return 0;
75}
76
77/**
78 * Copy |src_file_path| to |dest_file_path| if it exists.
79 *
80 * Returns 1 if |src_file_path| does not exist or not accessible,
81 * Returns -1 if the copy fails.
82 * Returns 0 if the copy succeeds.
83 */
84int copyFileIfItExists(
85 const std::string& src_file_path, const std::string& dest_file_path)
86{
87 int ret = access(src_file_path.c_str(), R_OK);
88 // Sepolicy denial (2018+ device) will return EACCESS instead of ENOENT.
89 if ((ret != 0) && ((errno == ENOENT) || (errno == EACCES))) {
90 return 1;
91 }
92 ret = copyFile(src_file_path, dest_file_path);
93 if (ret != 0) {
94 wpa_printf(
95 MSG_ERROR, "Failed copying %s to %s.",
96 src_file_path.c_str(), dest_file_path.c_str());
97 return -1;
98 }
99 return 0;
100}
101
102/**
103 * Ensure that the specified config file pointed by |config_file_path| exists.
104 * a) If the |config_file_path| exists with the correct permissions, return.
105 * b) If the |config_file_path| does not exist, but |old_config_file_path|
106 * exists, copy over the contents of the |old_config_file_path| to
107 * |config_file_path|.
108 * c) If the |config_file_path| & |old_config_file_path|
109 * does not exists, copy over the contents of |template_config_file_path|.
110 */
111int ensureConfigFileExists(
112 const std::string& config_file_path,
113 const std::string& old_config_file_path)
114{
115 int ret = access(config_file_path.c_str(), R_OK | W_OK);
116 if (ret == 0) {
117 return 0;
118 }
119 if (errno == EACCES) {
120 ret = chmod(config_file_path.c_str(), kConfigFileMode);
121 if (ret == 0) {
122 return 0;
123 } else {
124 wpa_printf(
125 MSG_ERROR, "Cannot set RW to %s. Errno: %s",
126 config_file_path.c_str(), strerror(errno));
127 return -1;
128 }
129 } else if (errno != ENOENT) {
130 wpa_printf(
131 MSG_ERROR, "Cannot acces %s. Errno: %s",
132 config_file_path.c_str(), strerror(errno));
133 return -1;
134 }
135 ret = copyFileIfItExists(old_config_file_path, config_file_path);
136 if (ret == 0) {
137 wpa_printf(
138 MSG_INFO, "Migrated conf file from %s to %s",
139 old_config_file_path.c_str(), config_file_path.c_str());
140 unlink(old_config_file_path.c_str());
141 return 0;
142 } else if (ret == -1) {
143 unlink(config_file_path.c_str());
144 return -1;
145 }
146 const char* path =
Sunil Ravi02df4482022-03-01 11:23:33 -0800147 resolvePath(kTemplateConfPaths,
148 sizeof(kTemplateConfPaths)/sizeof(kTemplateConfPaths[0]));
Gabriel Biren57ededa2021-09-03 16:08:50 +0000149 if (path != nullptr) {
150 ret = copyFileIfItExists(path, config_file_path);
151 if (ret == 0) {
152 wpa_printf(
153 MSG_INFO, "Copied template conf file from %s to %s",
154 path, config_file_path.c_str());
155 return 0;
156 } else if (ret == -1) {
157 unlink(config_file_path.c_str());
158 return -1;
159 }
160 }
161 // Did not create the conf file.
162 return -1;
163}
164} // namespace
165
166namespace aidl {
167namespace android {
168namespace hardware {
169namespace wifi {
170namespace supplicant {
171using aidl_return_util::validateAndCall;
172using misc_utils::createStatus;
173using misc_utils::createStatusWithMsg;
174
175Supplicant::Supplicant(struct wpa_global* global) : wpa_global_(global) {}
176bool Supplicant::isValid()
177{
178 // This top level object cannot be invalidated.
179 return true;
180}
181
182::ndk::ScopedAStatus Supplicant::addP2pInterface(
183 const std::string& in_name,
184 std::shared_ptr<ISupplicantP2pIface>* _aidl_return)
185{
186 return validateAndCall(
187 this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
188 &Supplicant::addP2pInterfaceInternal, _aidl_return, in_name);
189}
190
191::ndk::ScopedAStatus Supplicant::addStaInterface(
192 const std::string& in_name,
193 std::shared_ptr<ISupplicantStaIface>* _aidl_return)
194{
195 return validateAndCall(
196 this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
197 &Supplicant::addStaInterfaceInternal, _aidl_return, in_name);
198}
199
200::ndk::ScopedAStatus Supplicant::removeInterface(
201 const IfaceInfo& in_ifaceInfo)
202{
203 return validateAndCall(
204 this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
205 &Supplicant::removeInterfaceInternal, in_ifaceInfo);
206}
207
208::ndk::ScopedAStatus Supplicant::getP2pInterface(
209 const std::string& in_name,
210 std::shared_ptr<ISupplicantP2pIface>* _aidl_return)
211{
212 return validateAndCall(
213 this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
214 &Supplicant::getP2pInterfaceInternal, _aidl_return, in_name);
215}
216
217::ndk::ScopedAStatus Supplicant::getStaInterface(
218 const std::string& in_name,
219 std::shared_ptr<ISupplicantStaIface>* _aidl_return)
220{
221 return validateAndCall(
222 this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
223 &Supplicant::getStaInterfaceInternal, _aidl_return, in_name);
224}
225
226::ndk::ScopedAStatus Supplicant::listInterfaces(
227 std::vector<IfaceInfo>* _aidl_return)
228{
229 return validateAndCall(
230 this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
231 &Supplicant::listInterfacesInternal, _aidl_return);
232}
233
234::ndk::ScopedAStatus Supplicant::registerCallback(
235 const std::shared_ptr<ISupplicantCallback>& in_callback)
236{
237 return validateAndCall(
238 this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
239 &Supplicant::registerCallbackInternal, in_callback);
240}
241
242::ndk::ScopedAStatus Supplicant::setDebugParams(
243 DebugLevel in_level, bool in_showTimestamp,
244 bool in_showKeys)
245{
246 return validateAndCall(
247 this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
248 &Supplicant::setDebugParamsInternal, in_level,
249 in_showTimestamp, in_showKeys);
250}
251
252::ndk::ScopedAStatus Supplicant::setConcurrencyPriority(
253 IfaceType in_type)
254{
255 return validateAndCall(
256 this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
257 &Supplicant::setConcurrencyPriorityInternal, in_type);
258}
259
260::ndk::ScopedAStatus Supplicant::getDebugLevel(DebugLevel* _aidl_return)
261{
262 *_aidl_return = static_cast<DebugLevel>(wpa_debug_level);
263 return ndk::ScopedAStatus::ok();
264}
265
266::ndk::ScopedAStatus Supplicant::isDebugShowTimestampEnabled(bool* _aidl_return)
267{
268 *_aidl_return = ((wpa_debug_timestamp != 0) ? true : false);
269 return ndk::ScopedAStatus::ok();
270}
271
272::ndk::ScopedAStatus Supplicant::isDebugShowKeysEnabled(bool* _aidl_return)
273{
274 *_aidl_return = ((wpa_debug_show_keys != 0) ? true : false);
275 return ndk::ScopedAStatus::ok();
276}
277
278::ndk::ScopedAStatus Supplicant::terminate()
279{
280 wpa_printf(MSG_INFO, "Terminating...");
281 wpa_supplicant_terminate_proc(wpa_global_);
282 return ndk::ScopedAStatus::ok();
283}
284
285ndk::ScopedAStatus Supplicant::addP2pDevInterface(struct wpa_interface iface_params)
286{
287 char primary_ifname[IFNAMSIZ];
288 u32 primary_ifname_len =
289 strlen(iface_params.ifname) - strlen(P2P_MGMT_DEVICE_PREFIX);
290
291 if(primary_ifname_len > IFNAMSIZ) {
292 wpa_printf(MSG_DEBUG, "%s, Invalid primary iface name ", __FUNCTION__);
293 return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
294 }
295
296 strncpy(primary_ifname, iface_params.ifname +
297 strlen(P2P_MGMT_DEVICE_PREFIX), primary_ifname_len);
298 wpa_printf(MSG_DEBUG, "%s, Initialize p2p-dev-wlan0 iface with"
299 "primary_iface = %s", __FUNCTION__, primary_ifname);
300 struct wpa_supplicant* wpa_s =
301 wpa_supplicant_get_iface(wpa_global_, primary_ifname);
302 if (!wpa_s) {
303 wpa_printf(MSG_DEBUG, "%s,NULL wpa_s for wlan0", __FUNCTION__);
304 return createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN);
305 }
306 if (wpas_p2p_add_p2pdev_interface(
307 wpa_s, wpa_s->global->params.conf_p2p_dev) < 0) {
308 wpa_printf(MSG_INFO,
309 "Failed to enable P2P Device");
310 return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
311 }
312 return ndk::ScopedAStatus::ok();
313}
314
315std::pair<std::shared_ptr<ISupplicantP2pIface>, ndk::ScopedAStatus>
316Supplicant::addP2pInterfaceInternal(const std::string& name)
317{
318 std::shared_ptr<ISupplicantP2pIface> iface;
319
320 // Check if required |ifname| argument is empty.
321 if (name.empty()) {
322 return {nullptr, createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID)};
323 }
324 // Try to get the wpa_supplicant record for this iface, return
325 // the iface object with the appropriate status code if it exists.
326 ndk::ScopedAStatus status;
327 std::tie(iface, status) = getP2pInterfaceInternal(name);
328 if (status.isOk()) {
329 wpa_printf(MSG_INFO, "Iface already exists, return existing");
330 return {iface, ndk::ScopedAStatus::ok()};
331 }
332
333 struct wpa_interface iface_params = {};
334 iface_params.driver = kIfaceDriverName;
335 if (ensureConfigFileExists(
336 kP2pIfaceConfPath, kOldP2pIfaceConfPath) != 0) {
337 wpa_printf(
338 MSG_ERROR, "Conf file does not exists: %s",
339 kP2pIfaceConfPath);
340 return {nullptr, createStatusWithMsg(
341 SupplicantStatusCode::FAILURE_UNKNOWN, "Conf file does not exist")};
342 }
343 iface_params.confname = kP2pIfaceConfPath;
344 const char* path = resolvePath(
345 kP2pIfaceConfOverlayPaths,
Sunil Ravi02df4482022-03-01 11:23:33 -0800346 sizeof(kP2pIfaceConfOverlayPaths)/sizeof(kP2pIfaceConfOverlayPaths[0]));
Gabriel Biren57ededa2021-09-03 16:08:50 +0000347 if (path != nullptr) {
348 iface_params.confanother = path;
349 }
350
351 iface_params.ifname = name.c_str();
352 if (strncmp(iface_params.ifname, P2P_MGMT_DEVICE_PREFIX,
353 strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
354 status = addP2pDevInterface(iface_params);
355 if (!status.isOk()) {
356 return {iface, createStatus(static_cast<SupplicantStatusCode>(
357 status.getServiceSpecificError()))};
358 }
359 } else {
360 struct wpa_supplicant* wpa_s =
361 wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL);
362 if (!wpa_s) {
363 return {nullptr, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
364 }
365 // Request the current scan results from the driver and update
366 // the local BSS list wpa_s->bss. This is to avoid a full scan
367 // while processing the connect request on newly created interface.
368 wpa_supplicant_update_scan_results(wpa_s);
369 }
370 // The supplicant core creates a corresponding aidl object via
371 // AidlManager when |wpa_supplicant_add_iface| is called.
372 return getP2pInterfaceInternal(name);
373}
374
375std::pair<std::shared_ptr<ISupplicantStaIface>, ndk::ScopedAStatus>
376Supplicant::addStaInterfaceInternal(const std::string& name)
377{
378 std::shared_ptr<ISupplicantStaIface> iface;
379
380 // Check if required |ifname| argument is empty.
381 if (name.empty()) {
382 return {nullptr, createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID)};
383 }
384 // Try to get the wpa_supplicant record for this iface, return
385 // the iface object with the appropriate status code if it exists.
386 ndk::ScopedAStatus status;
387 std::tie(iface, status) = getStaInterfaceInternal(name);
388 if (status.isOk()) {
389 wpa_printf(MSG_INFO, "Iface already exists, return existing");
390 return {iface, ndk::ScopedAStatus::ok()};
391 }
392
393 struct wpa_interface iface_params = {};
394 iface_params.driver = kIfaceDriverName;
395 if (ensureConfigFileExists(
396 kStaIfaceConfPath, kOldStaIfaceConfPath) != 0) {
397 wpa_printf(
398 MSG_ERROR, "Conf file does not exists: %s",
399 kStaIfaceConfPath);
400 return {nullptr, createStatusWithMsg(
401 SupplicantStatusCode::FAILURE_UNKNOWN, "Conf file does not exist")};
402 }
403 iface_params.confname = kStaIfaceConfPath;
404 const char* path = resolvePath(
405 kStaIfaceConfOverlayPaths,
Sunil Ravi02df4482022-03-01 11:23:33 -0800406 sizeof(kStaIfaceConfOverlayPaths)/sizeof(kStaIfaceConfOverlayPaths[0]));
Gabriel Biren57ededa2021-09-03 16:08:50 +0000407 if (path != nullptr) {
408 iface_params.confanother = path;
409 }
410
411 iface_params.ifname = name.c_str();
412 if (strncmp(iface_params.ifname, P2P_MGMT_DEVICE_PREFIX,
413 strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
414 status = addP2pDevInterface(iface_params);
415 if (!status.isOk()) {
416 return {iface, createStatus(static_cast<SupplicantStatusCode>(
417 status.getServiceSpecificError()))};
418 }
419 } else {
420 struct wpa_supplicant* wpa_s =
421 wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL);
422 if (!wpa_s) {
423 return {nullptr, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
424 }
425 // Request the current scan results from the driver and update
426 // the local BSS list wpa_s->bss. This is to avoid a full scan
427 // while processing the connect request on newly created interface.
428 wpa_supplicant_update_scan_results(wpa_s);
429 }
430 // The supplicant core creates a corresponding aidl object via
431 // AidlManager when |wpa_supplicant_add_iface| is called.
432 return getStaInterfaceInternal(name);
433}
434
435ndk::ScopedAStatus Supplicant::removeInterfaceInternal(
436 const IfaceInfo& iface_info)
437{
438 struct wpa_supplicant* wpa_s =
439 wpa_supplicant_get_iface(wpa_global_, iface_info.name.c_str());
440 if (!wpa_s) {
441 return createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN);
442 }
443 if (wpa_supplicant_remove_iface(wpa_global_, wpa_s, 0)) {
444 return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
445 }
446 return ndk::ScopedAStatus::ok();
447}
448
449std::pair<std::shared_ptr<ISupplicantP2pIface>, ndk::ScopedAStatus>
450Supplicant::getP2pInterfaceInternal(const std::string& name)
451{
452 struct wpa_supplicant* wpa_s =
453 wpa_supplicant_get_iface(wpa_global_, name.c_str());
454 if (!wpa_s) {
455 return {nullptr, createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN)};
456 }
457 AidlManager* aidl_manager = AidlManager::getInstance();
458 std::shared_ptr<ISupplicantP2pIface> iface;
459 if (!aidl_manager ||
460 aidl_manager->getP2pIfaceAidlObjectByIfname(
461 wpa_s->ifname, &iface)) {
462 return {iface, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
463 }
464 // Set this flag true here, since there is no AIDL initialize
465 // method for the p2p config, and the supplicant interface is
466 // not ready when the p2p iface is created.
467 wpa_s->conf->persistent_reconnect = true;
468 return {iface, ndk::ScopedAStatus::ok()};
469}
470
471std::pair<std::shared_ptr<ISupplicantStaIface>, ndk::ScopedAStatus>
472Supplicant::getStaInterfaceInternal(const std::string& name)
473{
474 struct wpa_supplicant* wpa_s =
475 wpa_supplicant_get_iface(wpa_global_, name.c_str());
476 if (!wpa_s) {
477 return {nullptr, createStatus(SupplicantStatusCode::FAILURE_IFACE_UNKNOWN)};
478 }
479 AidlManager* aidl_manager = AidlManager::getInstance();
480 std::shared_ptr<ISupplicantStaIface> iface;
481 if (!aidl_manager ||
482 aidl_manager->getStaIfaceAidlObjectByIfname(
483 wpa_s->ifname, &iface)) {
484 return {iface, createStatus(SupplicantStatusCode::FAILURE_UNKNOWN)};
485 }
486 return {iface, ndk::ScopedAStatus::ok()};
487}
488
489std::pair<std::vector<IfaceInfo>, ndk::ScopedAStatus>
490Supplicant::listInterfacesInternal()
491{
492 std::vector<IfaceInfo> ifaces;
493 for (struct wpa_supplicant* wpa_s = wpa_global_->ifaces; wpa_s;
494 wpa_s = wpa_s->next) {
495 if (wpa_s->global->p2p_init_wpa_s == wpa_s) {
496 ifaces.emplace_back(IfaceInfo{
497 IfaceType::P2P, wpa_s->ifname});
498 } else {
499 ifaces.emplace_back(IfaceInfo{
500 IfaceType::STA, wpa_s->ifname});
501 }
502 }
503 return {std::move(ifaces), ndk::ScopedAStatus::ok()};
504}
505
506ndk::ScopedAStatus Supplicant::registerCallbackInternal(
507 const std::shared_ptr<ISupplicantCallback>& callback)
508{
509 AidlManager* aidl_manager = AidlManager::getInstance();
510 if (!aidl_manager ||
511 aidl_manager->addSupplicantCallbackAidlObject(callback)) {
512 return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
513 }
514 return ndk::ScopedAStatus::ok();
515}
516
517ndk::ScopedAStatus Supplicant::setDebugParamsInternal(
518 DebugLevel level, bool show_timestamp, bool show_keys)
519{
520 if (wpa_supplicant_set_debug_params(
521 wpa_global_, static_cast<uint32_t>(level), show_timestamp,
522 show_keys)) {
523 return createStatus(SupplicantStatusCode::FAILURE_UNKNOWN);
524 }
525 return ndk::ScopedAStatus::ok();
526}
527
528ndk::ScopedAStatus Supplicant::setConcurrencyPriorityInternal(IfaceType type)
529{
530 if (type == IfaceType::STA) {
531 wpa_global_->conc_pref =
532 wpa_global::wpa_conc_pref::WPA_CONC_PREF_STA;
533 } else if (type == IfaceType::P2P) {
534 wpa_global_->conc_pref =
535 wpa_global::wpa_conc_pref::WPA_CONC_PREF_P2P;
536 } else {
537 return createStatus(SupplicantStatusCode::FAILURE_ARGS_INVALID);
538 }
539 return ndk::ScopedAStatus::ok();
540}
541} // namespace supplicant
542} // namespace wifi
543} // namespace hardware
544} // namespace android
545} // namespace aidl