1 /* 2 * hidl interface for wpa_supplicant daemon 3 * Copyright (c) 2004-2016, Jouni Malinen <j (at) w1.fi> 4 * Copyright (c) 2004-2016, Roshan Pius <rpius (at) 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 18 namespace { 19 constexpr char kStaIfaceConfPath[] = 20 "/data/misc/wifi/wpa_supplicant.conf"; 21 constexpr char kP2pIfaceConfPath[] = 22 "/data/misc/wifi/p2p_supplicant.conf"; 23 // Migrate conf files for existing devices. 24 constexpr char kTemplateConfPath[] = 25 "/vendor/etc/wifi/wpa_supplicant.conf"; 26 constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; 27 28 int copyFile( 29 const std::string& src_file_path, const std::string& dest_file_path) 30 { 31 std::string file_contents; 32 if (!android::base::ReadFileToString(src_file_path, &file_contents)) { 33 wpa_printf( 34 MSG_ERROR, "Failed to read from %s. Errno: %s", 35 src_file_path.c_str(), strerror(errno)); 36 return -1; 37 } 38 if (!android::base::WriteStringToFile( 39 file_contents, dest_file_path, kConfigFileMode, getuid(), 40 getgid())) { 41 wpa_printf( 42 MSG_ERROR, "Failed to write to %s. Errno: %s", 43 dest_file_path.c_str(), strerror(errno)); 44 return -1; 45 } 46 return 0; 47 } 48 49 /** 50 * Copy |src_file_path| to |dest_file_path| if it exists. 51 * 52 * Returns 1 if |src_file_path| does not exists, 53 * Returns -1 if the copy fails. 54 * Returns 0 if the copy succeeds. 55 */ 56 int copyFileIfItExists( 57 const std::string& src_file_path, const std::string& dest_file_path) 58 { 59 int ret = access(src_file_path.c_str(), R_OK); 60 if ((ret != 0) && (errno == ENOENT)) { 61 return 1; 62 } 63 ret = copyFile(src_file_path, dest_file_path); 64 if (ret != 0) { 65 wpa_printf( 66 MSG_ERROR, "Failed copying %s to %s.", 67 src_file_path.c_str(), dest_file_path.c_str()); 68 return -1; 69 } 70 return 0; 71 } 72 73 /** 74 * Ensure that the specified config file pointed by |config_file_path| exists. 75 * a) If the |config_file_path| exists with the correct permissions, return. 76 * b) If the |config_file_path| does not exists, copy over the contents of 77 * |template_config_file_path|. 78 */ 79 int copyTemplateConfigFileIfNotExists( 80 const std::string& config_file_path, 81 const std::string& template_config_file_path) 82 { 83 int ret = access(config_file_path.c_str(), R_OK | W_OK); 84 if (ret == 0) { 85 return 0; 86 } 87 if (errno == EACCES) { 88 ret = chmod(config_file_path.c_str(), kConfigFileMode); 89 if (ret == 0) { 90 return 0; 91 } else { 92 wpa_printf( 93 MSG_ERROR, "Cannot set RW to %s. Errno: %s", 94 config_file_path.c_str(), strerror(errno)); 95 return -1; 96 } 97 } else if (errno != ENOENT) { 98 wpa_printf( 99 MSG_ERROR, "Cannot acces %s. Errno: %s", 100 config_file_path.c_str(), strerror(errno)); 101 return -1; 102 } 103 ret = copyFileIfItExists(template_config_file_path, config_file_path); 104 if (ret == 0) { 105 wpa_printf( 106 MSG_INFO, "Copied template conf file from %s to %s", 107 template_config_file_path.c_str(), config_file_path.c_str()); 108 return 0; 109 } else if (ret == -1) { 110 unlink(config_file_path.c_str()); 111 return -1; 112 } 113 // Did not create the conf file. 114 return -1; 115 } 116 } // namespace 117 118 namespace android { 119 namespace hardware { 120 namespace wifi { 121 namespace supplicant { 122 namespace V1_0 { 123 namespace implementation { 124 using hidl_return_util::validateAndCall; 125 126 // These are hardcoded for android. 127 const char Supplicant::kDriverName[] = "nl80211"; 128 const char Supplicant::kConfigFilePath[] = 129 "/data/misc/wifi/wpa_supplicant.conf"; 130 131 Supplicant::Supplicant(struct wpa_global* global) : wpa_global_(global) {} 132 bool Supplicant::isValid() 133 { 134 // This top level object cannot be invalidated. 135 return true; 136 } 137 138 bool Supplicant::ensureConfigFileExists() 139 { 140 // To support Android P Wifi framework, make sure the config file exists. 141 if (copyTemplateConfigFileIfNotExists( 142 kStaIfaceConfPath, kTemplateConfPath) != 0) { 143 wpa_printf(MSG_ERROR, "Conf file does not exists: %s", 144 kStaIfaceConfPath); 145 return false; 146 } 147 // P2P configuration file is not madatory but required for some devices. 148 if (copyTemplateConfigFileIfNotExists( 149 kP2pIfaceConfPath, kTemplateConfPath) != 0) { 150 wpa_printf(MSG_INFO, "Conf file does not exists: %s", 151 kP2pIfaceConfPath); 152 } 153 return true; 154 } 155 156 Return<void> Supplicant::getInterface( 157 const IfaceInfo& iface_info, getInterface_cb _hidl_cb) 158 { 159 return validateAndCall( 160 this, SupplicantStatusCode::FAILURE_IFACE_INVALID, 161 &Supplicant::getInterfaceInternal, _hidl_cb, iface_info); 162 } 163 164 Return<void> Supplicant::listInterfaces(listInterfaces_cb _hidl_cb) 165 { 166 return validateAndCall( 167 this, SupplicantStatusCode::FAILURE_IFACE_INVALID, 168 &Supplicant::listInterfacesInternal, _hidl_cb); 169 } 170 171 Return<void> Supplicant::registerCallback( 172 const sp<ISupplicantCallback>& callback, registerCallback_cb _hidl_cb) 173 { 174 return validateAndCall( 175 this, SupplicantStatusCode::FAILURE_IFACE_INVALID, 176 &Supplicant::registerCallbackInternal, _hidl_cb, callback); 177 } 178 179 Return<void> Supplicant::setDebugParams( 180 ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys, 181 setDebugParams_cb _hidl_cb) 182 { 183 return validateAndCall( 184 this, SupplicantStatusCode::FAILURE_IFACE_INVALID, 185 &Supplicant::setDebugParamsInternal, _hidl_cb, level, 186 show_timestamp, show_keys); 187 } 188 189 Return<void> Supplicant::setConcurrencyPriority( 190 IfaceType type, setConcurrencyPriority_cb _hidl_cb) 191 { 192 return validateAndCall( 193 this, SupplicantStatusCode::FAILURE_IFACE_INVALID, 194 &Supplicant::setConcurrencyPriorityInternal, _hidl_cb, type); 195 } 196 197 Return<ISupplicant::DebugLevel> Supplicant::getDebugLevel() 198 { 199 // TODO: Add SupplicantStatus in this method return for uniformity with 200 // the other methods in supplicant HIDL interface. 201 return (ISupplicant::DebugLevel)wpa_debug_level; 202 } 203 204 Return<bool> Supplicant::isDebugShowTimestampEnabled() 205 { 206 // TODO: Add SupplicantStatus in this method return for uniformity with 207 // the other methods in supplicant HIDL interface. 208 return ((wpa_debug_timestamp != 0) ? true : false); 209 } 210 211 Return<bool> Supplicant::isDebugShowKeysEnabled() 212 { 213 // TODO: Add SupplicantStatus in this method return for uniformity with 214 // the other methods in supplicant HIDL interface. 215 return ((wpa_debug_show_keys != 0) ? true : false); 216 } 217 218 std::pair<SupplicantStatus, sp<ISupplicantIface>> 219 Supplicant::getInterfaceInternal(const IfaceInfo& iface_info) 220 { 221 struct wpa_supplicant* wpa_s = 222 wpa_supplicant_get_iface(wpa_global_, iface_info.name.c_str()); 223 if (!wpa_s) { 224 return {{SupplicantStatusCode::FAILURE_IFACE_UNKNOWN, ""}, 225 nullptr}; 226 } 227 HidlManager* hidl_manager = HidlManager::getInstance(); 228 if (iface_info.type == IfaceType::P2P) { 229 android::sp<ISupplicantP2pIface> iface; 230 if (!hidl_manager || 231 hidl_manager->getP2pIfaceHidlObjectByIfname( 232 wpa_s->ifname, &iface)) { 233 return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, 234 iface}; 235 } 236 // Set this flag true here, since there is no HIDL initialize method for the p2p 237 // config, and the supplicant interface is not ready when the p2p iface is created. 238 wpa_s->conf->persistent_reconnect = true; 239 return {{SupplicantStatusCode::SUCCESS, ""}, iface}; 240 } else { 241 android::sp<ISupplicantStaIface> iface; 242 if (!hidl_manager || 243 hidl_manager->getStaIfaceHidlObjectByIfname( 244 wpa_s->ifname, &iface)) { 245 return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, 246 iface}; 247 } 248 return {{SupplicantStatusCode::SUCCESS, ""}, iface}; 249 } 250 } 251 252 std::pair<SupplicantStatus, std::vector<ISupplicant::IfaceInfo>> 253 Supplicant::listInterfacesInternal() 254 { 255 std::vector<ISupplicant::IfaceInfo> ifaces; 256 for (struct wpa_supplicant* wpa_s = wpa_global_->ifaces; wpa_s; 257 wpa_s = wpa_s->next) { 258 if (wpa_s->global->p2p_init_wpa_s == wpa_s) { 259 ifaces.emplace_back(ISupplicant::IfaceInfo{ 260 IfaceType::P2P, wpa_s->ifname}); 261 } else { 262 ifaces.emplace_back(ISupplicant::IfaceInfo{ 263 IfaceType::STA, wpa_s->ifname}); 264 } 265 } 266 return {{SupplicantStatusCode::SUCCESS, ""}, std::move(ifaces)}; 267 } 268 269 SupplicantStatus Supplicant::registerCallbackInternal( 270 const sp<ISupplicantCallback>& callback) 271 { 272 HidlManager* hidl_manager = HidlManager::getInstance(); 273 if (!hidl_manager || 274 hidl_manager->addSupplicantCallbackHidlObject(callback)) { 275 return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; 276 } 277 return {SupplicantStatusCode::SUCCESS, ""}; 278 } 279 280 SupplicantStatus Supplicant::setDebugParamsInternal( 281 ISupplicant::DebugLevel level, bool show_timestamp, bool show_keys) 282 { 283 if (wpa_supplicant_set_debug_params( 284 wpa_global_, static_cast<uint32_t>(level), show_timestamp, 285 show_keys)) { 286 return {SupplicantStatusCode::FAILURE_UNKNOWN, ""}; 287 } 288 return {SupplicantStatusCode::SUCCESS, ""}; 289 } 290 291 SupplicantStatus Supplicant::setConcurrencyPriorityInternal(IfaceType type) 292 { 293 if (type == IfaceType::STA) { 294 wpa_global_->conc_pref = 295 wpa_global::wpa_conc_pref::WPA_CONC_PREF_STA; 296 } else if (type == IfaceType::P2P) { 297 wpa_global_->conc_pref = 298 wpa_global::wpa_conc_pref::WPA_CONC_PREF_P2P; 299 } else { 300 return {SupplicantStatusCode::FAILURE_ARGS_INVALID, ""}; 301 } 302 return SupplicantStatus{SupplicantStatusCode::SUCCESS, ""}; 303 } 304 } // namespace implementation 305 } // namespace V1_0 306 } // namespace wifi 307 } // namespace supplicant 308 } // namespace hardware 309 } // namespace android 310