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 20extern "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. 30namespace { 31constexpr char kConfFileNameFmt[] = "/data/vendor/wifi/hostapd/hostapd_%s.conf"; 32 33using android::base::RemoveFileIfExists; 34using android::base::StringPrintf; 35using android::base::WriteStringToFile; 36using android::hardware::wifi::hostapd::V1_0::IHostapd; 37 38std::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 68std::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.channelParams.enableAcs) { 130 channel_config_as_string = StringPrintf( 131 "channel=0\n" 132 "acs_exclude_dfs=%d", 133 iface_params.channelParams.acsShouldExcludeDfs); 134 } else { 135 channel_config_as_string = StringPrintf( 136 "channel=%d", iface_params.channelParams.channel); 137 } 138 139 // Hw Mode String 140 std::string hw_mode_as_string; 141 std::string ht_cap_vht_oper_chwidth_as_string; 142 switch (iface_params.channelParams.band) { 143 case IHostapd::Band::BAND_2_4_GHZ: 144 hw_mode_as_string = "hw_mode=g"; 145 break; 146 case IHostapd::Band::BAND_5_GHZ: 147 hw_mode_as_string = "hw_mode=a"; 148 if (iface_params.channelParams.enableAcs) { 149 ht_cap_vht_oper_chwidth_as_string = 150 "ht_capab=[HT40+]\n" 151 "vht_oper_chwidth=1"; 152 } 153 break; 154 case IHostapd::Band::BAND_ANY: 155 hw_mode_as_string = "hw_mode=any"; 156 if (iface_params.channelParams.enableAcs) { 157 ht_cap_vht_oper_chwidth_as_string = 158 "ht_capab=[HT40+]\n" 159 "vht_oper_chwidth=1"; 160 } 161 break; 162 default: 163 wpa_printf(MSG_ERROR, "Invalid band"); 164 return ""; 165 } 166 167 return StringPrintf( 168 "interface=%s\n" 169 "driver=nl80211\n" 170 "ctrl_interface=/data/vendor/wifi/hostapd/ctrl\n" 171 // ssid2 signals to hostapd that the value is not a literal value 172 // for use as a SSID. In this case, we're giving it a hex 173 // std::string and hostapd needs to expect that. 174 "ssid2=%s\n" 175 "%s\n" 176 "ieee80211n=%d\n" 177 "ieee80211ac=%d\n" 178 "%s\n" 179 "%s\n" 180 "ignore_broadcast_ssid=%d\n" 181 "wowlan_triggers=any\n" 182 "%s\n", 183 iface_params.ifaceName.c_str(), ssid_as_string.c_str(), 184 channel_config_as_string.c_str(), 185 iface_params.hwModeParams.enable80211N ? 1 : 0, 186 iface_params.hwModeParams.enable80211AC ? 1 : 0, 187 hw_mode_as_string.c_str(), ht_cap_vht_oper_chwidth_as_string.c_str(), 188 nw_params.isHidden ? 1 : 0, encryption_config_as_string.c_str()); 189} 190} // namespace 191 192namespace android { 193namespace hardware { 194namespace wifi { 195namespace hostapd { 196namespace V1_0 { 197namespace implementation { 198using hidl_return_util::call; 199 200Hostapd::Hostapd(struct hapd_interfaces* interfaces) : interfaces_(interfaces) 201{} 202 203Return<void> Hostapd::addAccessPoint( 204 const IfaceParams& iface_params, const NetworkParams& nw_params, 205 addAccessPoint_cb _hidl_cb) 206{ 207 return call( 208 this, &Hostapd::addAccessPointInternal, _hidl_cb, iface_params, 209 nw_params); 210} 211 212Return<void> Hostapd::removeAccessPoint( 213 const hidl_string& iface_name, removeAccessPoint_cb _hidl_cb) 214{ 215 return call( 216 this, &Hostapd::removeAccessPointInternal, _hidl_cb, iface_name); 217} 218 219Return<void> Hostapd::terminate() { 220 wpa_printf(MSG_INFO, "Terminating..."); 221 eloop_terminate(); 222 return Void(); 223} 224 225HostapdStatus Hostapd::addAccessPointInternal( 226 const IfaceParams& iface_params, const NetworkParams& nw_params) 227{ 228 if (hostapd_get_iface(interfaces_, iface_params.ifaceName.c_str())) { 229 wpa_printf( 230 MSG_ERROR, "Interface %s already present", 231 iface_params.ifaceName.c_str()); 232 return {HostapdStatusCode::FAILURE_IFACE_EXISTS, ""}; 233 } 234 const auto conf_params = CreateHostapdConfig(iface_params, nw_params); 235 if (conf_params.empty()) { 236 wpa_printf(MSG_ERROR, "Failed to create config params"); 237 return {HostapdStatusCode::FAILURE_ARGS_INVALID, ""}; 238 } 239 const auto conf_file_path = 240 WriteHostapdConfig(iface_params.ifaceName, conf_params); 241 if (conf_file_path.empty()) { 242 wpa_printf(MSG_ERROR, "Failed to write config file"); 243 return {HostapdStatusCode::FAILURE_UNKNOWN, ""}; 244 } 245 std::string add_iface_param_str = StringPrintf( 246 "%s config=%s", iface_params.ifaceName.c_str(), 247 conf_file_path.c_str()); 248 std::vector<char> add_iface_param_vec( 249 add_iface_param_str.begin(), add_iface_param_str.end() + 1); 250 if (hostapd_add_iface(interfaces_, add_iface_param_vec.data()) < 0) { 251 wpa_printf( 252 MSG_ERROR, "Adding interface %s failed", 253 add_iface_param_str.c_str()); 254 return {HostapdStatusCode::FAILURE_UNKNOWN, ""}; 255 } 256 struct hostapd_data* iface_hapd = 257 hostapd_get_iface(interfaces_, iface_params.ifaceName.c_str()); 258 WPA_ASSERT(iface_hapd != nullptr && iface_hapd->iface != nullptr); 259 if (hostapd_enable_iface(iface_hapd->iface) < 0) { 260 wpa_printf( 261 MSG_ERROR, "Enabling interface %s failed", 262 iface_params.ifaceName.c_str()); 263 return {HostapdStatusCode::FAILURE_UNKNOWN, ""}; 264 } 265 return {HostapdStatusCode::SUCCESS, ""}; 266} 267 268HostapdStatus Hostapd::removeAccessPointInternal(const std::string& iface_name) 269{ 270 std::vector<char> remove_iface_param_vec( 271 iface_name.begin(), iface_name.end() + 1); 272 if (hostapd_remove_iface(interfaces_, remove_iface_param_vec.data()) < 273 0) { 274 wpa_printf( 275 MSG_ERROR, "Removing interface %s failed", 276 iface_name.c_str()); 277 return {HostapdStatusCode::FAILURE_UNKNOWN, ""}; 278 } 279 return {HostapdStatusCode::SUCCESS, ""}; 280} 281} // namespace implementation 282} // namespace V1_0 283} // namespace hostapd 284} // namespace wifi 285} // namespace hardware 286} // namespace android 287