Files
android_external_wpa_suppli…/hostapd/aidl/hostapd.cpp
Sunil Ravi 4fc918fad8 set the hostapd channel bandwidth
This change takes care of setting the channel
bandwidth when framework doesn't provide the bandwidth.
Changes are,
1. 40MHz bandwidth in 2.4GHz band is not common and
is prone to inter-op issues. So disable setting 40MHz
in 2.4GHz band only configuration and cases where 60GHz
is used.
2. Set 40MHz & vht operational channel width only in 5GHz and 6GHz
when 11AC is enabled and 60GHz is not used cases.
3. set he operational channel width when 11ax is enabled and
60GHz is not used cases.

Bug: 213122226
Test: atest android.net.wifi.cts.WifiManagerTest
Test: adb shell cmd wifi force-softap-channel enabled 2412
Change-Id: I4e707d709f885daa5dcc7fdcafbfad751e3a62e1
2022-04-18 21:53:06 -07:00

1127 lines
33 KiB
C++

/*
* aidl interface for wpa_hostapd daemon
* Copyright (c) 2004-2018, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2018, Roshan Pius <rpius@google.com>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <net/if.h>
#include <sys/socket.h>
#include <linux/if_bridge.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include "hostapd.h"
#include <aidl/android/hardware/wifi/hostapd/ApInfo.h>
#include <aidl/android/hardware/wifi/hostapd/BandMask.h>
#include <aidl/android/hardware/wifi/hostapd/ChannelParams.h>
#include <aidl/android/hardware/wifi/hostapd/ClientInfo.h>
#include <aidl/android/hardware/wifi/hostapd/EncryptionType.h>
#include <aidl/android/hardware/wifi/hostapd/HostapdStatusCode.h>
#include <aidl/android/hardware/wifi/hostapd/IfaceParams.h>
#include <aidl/android/hardware/wifi/hostapd/NetworkParams.h>
#include <aidl/android/hardware/wifi/hostapd/ParamSizeLimits.h>
extern "C"
{
#include "common/wpa_ctrl.h"
#include "drivers/linux_ioctl.h"
}
// The AIDL implementation for hostapd creates a hostapd.conf dynamically for
// each interface. This file can then be used to hook onto the normal config
// file parsing logic in hostapd code. Helps us to avoid duplication of code
// in the AIDL interface.
// TOOD(b/71872409): Add unit tests for this.
namespace {
constexpr char kConfFileNameFmt[] = "/data/vendor/wifi/hostapd/hostapd_%s.conf";
using android::base::RemoveFileIfExists;
using android::base::StringPrintf;
using android::base::WriteStringToFile;
using aidl::android::hardware::wifi::hostapd::BandMask;
using aidl::android::hardware::wifi::hostapd::ChannelBandwidth;
using aidl::android::hardware::wifi::hostapd::ChannelParams;
using aidl::android::hardware::wifi::hostapd::EncryptionType;
using aidl::android::hardware::wifi::hostapd::Generation;
using aidl::android::hardware::wifi::hostapd::HostapdStatusCode;
using aidl::android::hardware::wifi::hostapd::IfaceParams;
using aidl::android::hardware::wifi::hostapd::NetworkParams;
using aidl::android::hardware::wifi::hostapd::ParamSizeLimits;
int band2Ghz = (int)BandMask::BAND_2_GHZ;
int band5Ghz = (int)BandMask::BAND_5_GHZ;
int band6Ghz = (int)BandMask::BAND_6_GHZ;
int band60Ghz = (int)BandMask::BAND_60_GHZ;
#define MAX_PORTS 1024
bool GetInterfacesInBridge(std::string br_name,
std::vector<std::string>* interfaces) {
android::base::unique_fd sock(socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0));
if (sock.get() < 0) {
wpa_printf(MSG_ERROR, "Failed to create sock (%s) in %s",
strerror(errno), __FUNCTION__);
return false;
}
struct ifreq request;
int i, ifindices[MAX_PORTS];
char if_name[IFNAMSIZ];
unsigned long args[3];
memset(ifindices, 0, MAX_PORTS * sizeof(int));
args[0] = BRCTL_GET_PORT_LIST;
args[1] = (unsigned long) ifindices;
args[2] = MAX_PORTS;
strlcpy(request.ifr_name, br_name.c_str(), IFNAMSIZ);
request.ifr_data = (char *)args;
if (ioctl(sock.get(), SIOCDEVPRIVATE, &request) < 0) {
wpa_printf(MSG_ERROR, "Failed to ioctl SIOCDEVPRIVATE in %s",
__FUNCTION__);
return false;
}
for (i = 0; i < MAX_PORTS; i ++) {
memset(if_name, 0, IFNAMSIZ);
if (ifindices[i] == 0 || !if_indextoname(ifindices[i], if_name)) {
continue;
}
interfaces->push_back(if_name);
}
return true;
}
std::string WriteHostapdConfig(
const std::string& interface_name, const std::string& config)
{
const std::string file_path =
StringPrintf(kConfFileNameFmt, interface_name.c_str());
if (WriteStringToFile(
config, file_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
getuid(), getgid())) {
return file_path;
}
// Diagnose failure
int error = errno;
wpa_printf(
MSG_ERROR, "Cannot write hostapd config to %s, error: %s",
file_path.c_str(), strerror(error));
struct stat st;
int result = stat(file_path.c_str(), &st);
if (result == 0) {
wpa_printf(
MSG_ERROR, "hostapd config file uid: %d, gid: %d, mode: %d",
st.st_uid, st.st_gid, st.st_mode);
} else {
wpa_printf(
MSG_ERROR,
"Error calling stat() on hostapd config file: %s",
strerror(errno));
}
return "";
}
/*
* Get the op_class for a channel/band
* The logic here is based on Table E-4 in the 802.11 Specification
*/
int getOpClassForChannel(int channel, int band, bool support11n, bool support11ac) {
// 2GHz Band
if ((band & band2Ghz) != 0) {
if (channel == 14) {
return 82;
}
if (channel >= 1 && channel <= 13) {
if (!support11n) {
//20MHz channel
return 81;
}
if (channel <= 9) {
// HT40 with secondary channel above primary
return 83;
}
// HT40 with secondary channel below primary
return 84;
}
// Error
return 0;
}
// 5GHz Band
if ((band & band5Ghz) != 0) {
if (support11ac) {
switch (channel) {
case 42:
case 58:
case 106:
case 122:
case 138:
case 155:
// 80MHz channel
return 128;
case 50:
case 114:
// 160MHz channel
return 129;
}
}
if (!support11n) {
if (channel >= 36 && channel <= 48) {
return 115;
}
if (channel >= 52 && channel <= 64) {
return 118;
}
if (channel >= 100 && channel <= 144) {
return 121;
}
if (channel >= 149 && channel <= 161) {
return 124;
}
if (channel >= 165 && channel <= 169) {
return 125;
}
} else {
switch (channel) {
case 36:
case 44:
// HT40 with secondary channel above primary
return 116;
case 40:
case 48:
// HT40 with secondary channel below primary
return 117;
case 52:
case 60:
// HT40 with secondary channel above primary
return 119;
case 56:
case 64:
// HT40 with secondary channel below primary
return 120;
case 100:
case 108:
case 116:
case 124:
case 132:
case 140:
// HT40 with secondary channel above primary
return 122;
case 104:
case 112:
case 120:
case 128:
case 136:
case 144:
// HT40 with secondary channel below primary
return 123;
case 149:
case 157:
// HT40 with secondary channel above primary
return 126;
case 153:
case 161:
// HT40 with secondary channel below primary
return 127;
}
}
// Error
return 0;
}
// 6GHz Band
if ((band & band6Ghz) != 0) {
// Channels 1, 5. 9, 13, ...
if ((channel & 0x03) == 0x01) {
// 20MHz channel
return 131;
}
// Channels 3, 11, 19, 27, ...
if ((channel & 0x07) == 0x03) {
// 40MHz channel
return 132;
}
// Channels 7, 23, 39, 55, ...
if ((channel & 0x0F) == 0x07) {
// 80MHz channel
return 133;
}
// Channels 15, 47, 69, ...
if ((channel & 0x1F) == 0x0F) {
// 160MHz channel
return 134;
}
if (channel == 2) {
// 20MHz channel
return 136;
}
// Error
return 0;
}
if ((band & band60Ghz) != 0) {
if (1 <= channel && channel <= 8) {
return 180;
} else if (9 <= channel && channel <= 15) {
return 181;
} else if (17 <= channel && channel <= 22) {
return 182;
} else if (25 <= channel && channel <= 29) {
return 183;
}
// Error
return 0;
}
return 0;
}
bool validatePassphrase(int passphrase_len, int min_len, int max_len)
{
if (min_len != -1 && passphrase_len < min_len) return false;
if (max_len != -1 && passphrase_len > max_len) return false;
return true;
}
std::string CreateHostapdConfig(
const IfaceParams& iface_params,
const ChannelParams& channelParams,
const NetworkParams& nw_params,
const std::string br_name,
const std::string owe_transition_ifname)
{
if (nw_params.ssid.size() >
static_cast<uint32_t>(
ParamSizeLimits::SSID_MAX_LEN_IN_BYTES)) {
wpa_printf(
MSG_ERROR, "Invalid SSID size: %zu", nw_params.ssid.size());
return "";
}
// SSID string
std::stringstream ss;
ss << std::hex;
ss << std::setfill('0');
for (uint8_t b : nw_params.ssid) {
ss << std::setw(2) << static_cast<unsigned int>(b);
}
const std::string ssid_as_string = ss.str();
// Encryption config string
uint32_t band = 0;
band |= static_cast<uint32_t>(channelParams.bandMask);
bool is_2Ghz_band_only = band == static_cast<uint32_t>(band2Ghz);
bool is_6Ghz_band_only = band == static_cast<uint32_t>(band6Ghz);
bool is_60Ghz_band_only = band == static_cast<uint32_t>(band60Ghz);
std::string encryption_config_as_string;
switch (nw_params.encryptionType) {
case EncryptionType::NONE:
// no security params
break;
case EncryptionType::WPA:
if (!validatePassphrase(
nw_params.passphrase.size(),
static_cast<uint32_t>(ParamSizeLimits::
WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
static_cast<uint32_t>(ParamSizeLimits::
WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
return "";
}
encryption_config_as_string = StringPrintf(
"wpa=3\n"
"wpa_pairwise=%s\n"
"wpa_passphrase=%s",
is_60Ghz_band_only ? "GCMP" : "TKIP CCMP",
nw_params.passphrase.c_str());
break;
case EncryptionType::WPA2:
if (!validatePassphrase(
nw_params.passphrase.size(),
static_cast<uint32_t>(ParamSizeLimits::
WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
static_cast<uint32_t>(ParamSizeLimits::
WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
return "";
}
encryption_config_as_string = StringPrintf(
"wpa=2\n"
"rsn_pairwise=%s\n"
#ifdef ENABLE_HOSTAPD_CONFIG_80211W_MFP_OPTIONAL
"ieee80211w=1\n"
#endif
"wpa_passphrase=%s",
is_60Ghz_band_only ? "GCMP" : "CCMP",
nw_params.passphrase.c_str());
break;
case EncryptionType::WPA3_SAE_TRANSITION:
if (!validatePassphrase(
nw_params.passphrase.size(),
static_cast<uint32_t>(ParamSizeLimits::
WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES),
static_cast<uint32_t>(ParamSizeLimits::
WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES))) {
return "";
}
encryption_config_as_string = StringPrintf(
"wpa=2\n"
"rsn_pairwise=%s\n"
"wpa_key_mgmt=WPA-PSK SAE\n"
"ieee80211w=1\n"
"sae_require_mfp=1\n"
"wpa_passphrase=%s\n"
"sae_password=%s",
is_60Ghz_band_only ? "GCMP" : "CCMP",
nw_params.passphrase.c_str(),
nw_params.passphrase.c_str());
break;
case EncryptionType::WPA3_SAE:
if (!validatePassphrase(nw_params.passphrase.size(), 1, -1)) {
return "";
}
encryption_config_as_string = StringPrintf(
"wpa=2\n"
"rsn_pairwise=%s\n"
"wpa_key_mgmt=SAE\n"
"ieee80211w=2\n"
"sae_require_mfp=2\n"
"sae_pwe=%d\n"
"sae_password=%s",
is_60Ghz_band_only ? "GCMP" : "CCMP",
is_6Ghz_band_only ? 1 : 2,
nw_params.passphrase.c_str());
break;
case EncryptionType::WPA3_OWE_TRANSITION:
encryption_config_as_string = StringPrintf(
"wpa=2\n"
"rsn_pairwise=%s\n"
"wpa_key_mgmt=OWE\n"
"ieee80211w=2",
is_60Ghz_band_only ? "GCMP" : "CCMP");
break;
case EncryptionType::WPA3_OWE:
encryption_config_as_string = StringPrintf(
"wpa=2\n"
"rsn_pairwise=%s\n"
"wpa_key_mgmt=OWE\n"
"ieee80211w=2",
is_60Ghz_band_only ? "GCMP" : "CCMP");
break;
default:
wpa_printf(MSG_ERROR, "Unknown encryption type");
return "";
}
std::string channel_config_as_string;
bool isFirst = true;
if (channelParams.enableAcs) {
std::string freqList_as_string;
for (const auto &range :
channelParams.acsChannelFreqRangesMhz) {
if (!isFirst) {
freqList_as_string += ",";
}
isFirst = false;
if (range.startMhz != range.endMhz) {
freqList_as_string +=
StringPrintf("%d-%d", range.startMhz, range.endMhz);
} else {
freqList_as_string += StringPrintf("%d", range.startMhz);
}
}
channel_config_as_string = StringPrintf(
"channel=0\n"
"acs_exclude_dfs=%d\n"
"freqlist=%s",
channelParams.acsShouldExcludeDfs,
freqList_as_string.c_str());
} else {
int op_class = getOpClassForChannel(
channelParams.channel,
band,
iface_params.hwModeParams.enable80211N,
iface_params.hwModeParams.enable80211AC);
channel_config_as_string = StringPrintf(
"channel=%d\n"
"op_class=%d",
channelParams.channel, op_class);
}
std::string hw_mode_as_string;
std::string enable_edmg_as_string;
std::string edmg_channel_as_string;
bool is_60Ghz_used = false;
if (((band & band60Ghz) != 0)) {
hw_mode_as_string = "hw_mode=ad";
if (iface_params.hwModeParams.enableEdmg) {
enable_edmg_as_string = "enable_edmg=1";
edmg_channel_as_string = StringPrintf(
"edmg_channel=%d",
channelParams.channel);
}
is_60Ghz_used = true;
} else if ((band & band2Ghz) != 0) {
if (((band & band5Ghz) != 0)
|| ((band & band6Ghz) != 0)) {
hw_mode_as_string = "hw_mode=any";
} else {
hw_mode_as_string = "hw_mode=g";
}
} else if (((band & band5Ghz) != 0)
|| ((band & band6Ghz) != 0)) {
hw_mode_as_string = "hw_mode=a";
} else {
wpa_printf(MSG_ERROR, "Invalid band");
return "";
}
std::string he_params_as_string;
#ifdef CONFIG_IEEE80211AX
if (iface_params.hwModeParams.enable80211AX && !is_60Ghz_used) {
he_params_as_string = StringPrintf(
"ieee80211ax=1\n"
"he_su_beamformer=%d\n"
"he_su_beamformee=%d\n"
"he_mu_beamformer=%d\n"
"he_twt_required=%d\n",
iface_params.hwModeParams.enableHeSingleUserBeamformer ? 1 : 0,
iface_params.hwModeParams.enableHeSingleUserBeamformee ? 1 : 0,
iface_params.hwModeParams.enableHeMultiUserBeamformer ? 1 : 0,
iface_params.hwModeParams.enableHeTargetWakeTime ? 1 : 0);
} else {
he_params_as_string = "ieee80211ax=0";
}
#endif /* CONFIG_IEEE80211AX */
std::string ht_cap_vht_oper_he_oper_chwidth_as_string;
switch (iface_params.hwModeParams.maximumChannelBandwidth) {
case ChannelBandwidth::BANDWIDTH_20:
ht_cap_vht_oper_he_oper_chwidth_as_string = StringPrintf(
#ifdef CONFIG_IEEE80211AX
"he_oper_chwidth=0\n"
#endif
"vht_oper_chwidth=0");
break;
case ChannelBandwidth::BANDWIDTH_40:
ht_cap_vht_oper_he_oper_chwidth_as_string = StringPrintf(
"ht_capab=[HT40+]\n"
#ifdef CONFIG_IEEE80211AX
"he_oper_chwidth=0\n"
#endif
"vht_oper_chwidth=0");
break;
case ChannelBandwidth::BANDWIDTH_80:
ht_cap_vht_oper_he_oper_chwidth_as_string = StringPrintf(
"ht_capab=[HT40+]\n"
#ifdef CONFIG_IEEE80211AX
"he_oper_chwidth=%d\n"
#endif
"vht_oper_chwidth=%d",
#ifdef CONFIG_IEEE80211AX
(iface_params.hwModeParams.enable80211AX && !is_60Ghz_used) ? 1 : 0,
#endif
iface_params.hwModeParams.enable80211AC ? 1 : 0);
break;
case ChannelBandwidth::BANDWIDTH_160:
ht_cap_vht_oper_he_oper_chwidth_as_string = StringPrintf(
"ht_capab=[HT40+]\n"
#ifdef CONFIG_IEEE80211AX
"he_oper_chwidth=%d\n"
#endif
"vht_oper_chwidth=%d",
#ifdef CONFIG_IEEE80211AX
(iface_params.hwModeParams.enable80211AX && !is_60Ghz_used) ? 2 : 0,
#endif
iface_params.hwModeParams.enable80211AC ? 2 : 0);
break;
default:
if (!is_2Ghz_band_only && !is_60Ghz_used
&& iface_params.hwModeParams.enable80211AC) {
ht_cap_vht_oper_he_oper_chwidth_as_string =
"ht_capab=[HT40+]\n"
"vht_oper_chwidth=1\n";
}
#ifdef CONFIG_IEEE80211AX
if (iface_params.hwModeParams.enable80211AX && !is_60Ghz_used) {
ht_cap_vht_oper_he_oper_chwidth_as_string += "he_oper_chwidth=1";
}
#endif
break;
}
#ifdef CONFIG_INTERWORKING
std::string access_network_params_as_string;
if (nw_params.isMetered) {
access_network_params_as_string = StringPrintf(
"interworking=1\n"
"access_network_type=2\n"); // CHARGEABLE_PUBLIC_NETWORK
} else {
access_network_params_as_string = StringPrintf(
"interworking=0\n");
}
#endif /* CONFIG_INTERWORKING */
std::string bridge_as_string;
if (!br_name.empty()) {
bridge_as_string = StringPrintf("bridge=%s", br_name.c_str());
}
// vendor_elements string
std::string vendor_elements_as_string;
if (nw_params.vendorElements.size() > 0) {
std::stringstream ss;
ss << std::hex;
ss << std::setfill('0');
for (uint8_t b : nw_params.vendorElements) {
ss << std::setw(2) << static_cast<unsigned int>(b);
}
vendor_elements_as_string = StringPrintf("vendor_elements=%s", ss.str().c_str());
}
std::string owe_transition_ifname_as_string;
if (!owe_transition_ifname.empty()) {
owe_transition_ifname_as_string = StringPrintf(
"owe_transition_ifname=%s", owe_transition_ifname.c_str());
}
return StringPrintf(
"interface=%s\n"
"driver=nl80211\n"
"ctrl_interface=/data/vendor/wifi/hostapd/ctrl\n"
// ssid2 signals to hostapd that the value is not a literal value
// for use as a SSID. In this case, we're giving it a hex
// std::string and hostapd needs to expect that.
"ssid2=%s\n"
"%s\n"
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
"%s\n"
"%s\n"
"%s\n"
"ignore_broadcast_ssid=%d\n"
"wowlan_triggers=any\n"
#ifdef CONFIG_INTERWORKING
"%s\n"
#endif /* CONFIG_INTERWORKING */
"%s\n"
"%s\n"
"%s\n"
"%s\n"
"%s\n"
"%s\n",
iface_params.name.c_str(), ssid_as_string.c_str(),
channel_config_as_string.c_str(),
iface_params.hwModeParams.enable80211N ? 1 : 0,
iface_params.hwModeParams.enable80211AC ? 1 : 0,
he_params_as_string.c_str(),
hw_mode_as_string.c_str(), ht_cap_vht_oper_he_oper_chwidth_as_string.c_str(),
nw_params.isHidden ? 1 : 0,
#ifdef CONFIG_INTERWORKING
access_network_params_as_string.c_str(),
#endif /* CONFIG_INTERWORKING */
encryption_config_as_string.c_str(),
bridge_as_string.c_str(),
owe_transition_ifname_as_string.c_str(),
enable_edmg_as_string.c_str(),
edmg_channel_as_string.c_str(),
vendor_elements_as_string.c_str());
}
Generation getGeneration(hostapd_hw_modes *current_mode)
{
wpa_printf(MSG_DEBUG, "getGeneration hwmode=%d, ht_enabled=%d,"
" vht_enabled=%d, he_supported=%d",
current_mode->mode, current_mode->ht_capab != 0,
current_mode->vht_capab != 0, current_mode->he_capab->he_supported);
switch (current_mode->mode) {
case HOSTAPD_MODE_IEEE80211B:
return Generation::WIFI_STANDARD_LEGACY;
case HOSTAPD_MODE_IEEE80211G:
return current_mode->ht_capab == 0 ?
Generation::WIFI_STANDARD_LEGACY : Generation::WIFI_STANDARD_11N;
case HOSTAPD_MODE_IEEE80211A:
if (current_mode->he_capab->he_supported) {
return Generation::WIFI_STANDARD_11AX;
}
return current_mode->vht_capab == 0 ?
Generation::WIFI_STANDARD_11N : Generation::WIFI_STANDARD_11AC;
case HOSTAPD_MODE_IEEE80211AD:
return Generation::WIFI_STANDARD_11AD;
default:
return Generation::WIFI_STANDARD_UNKNOWN;
}
}
ChannelBandwidth getChannelBandwidth(struct hostapd_config *iconf)
{
wpa_printf(MSG_DEBUG, "getChannelBandwidth %d, isHT=%d, isHT40=%d",
iconf->vht_oper_chwidth, iconf->ieee80211n,
iconf->secondary_channel);
switch (iconf->vht_oper_chwidth) {
case CHANWIDTH_80MHZ:
return ChannelBandwidth::BANDWIDTH_80;
case CHANWIDTH_80P80MHZ:
return ChannelBandwidth::BANDWIDTH_80P80;
break;
case CHANWIDTH_160MHZ:
return ChannelBandwidth::BANDWIDTH_160;
break;
case CHANWIDTH_USE_HT:
if (iconf->ieee80211n) {
return iconf->secondary_channel != 0 ?
ChannelBandwidth::BANDWIDTH_40 : ChannelBandwidth::BANDWIDTH_20;
}
return ChannelBandwidth::BANDWIDTH_20_NOHT;
case CHANWIDTH_2160MHZ:
return ChannelBandwidth::BANDWIDTH_2160;
case CHANWIDTH_4320MHZ:
return ChannelBandwidth::BANDWIDTH_4320;
case CHANWIDTH_6480MHZ:
return ChannelBandwidth::BANDWIDTH_6480;
case CHANWIDTH_8640MHZ:
return ChannelBandwidth::BANDWIDTH_8640;
default:
return ChannelBandwidth::BANDWIDTH_INVALID;
}
}
bool forceStaDisconnection(struct hostapd_data* hapd,
const std::vector<uint8_t>& client_address,
const uint16_t reason_code) {
struct sta_info *sta;
for (sta = hapd->sta_list; sta; sta = sta->next) {
int res;
res = memcmp(sta->addr, client_address.data(), ETH_ALEN);
if (res == 0) {
wpa_printf(MSG_INFO, "Force client:" MACSTR " disconnect with reason: %d",
MAC2STR(client_address.data()), reason_code);
ap_sta_disconnect(hapd, sta, sta->addr, reason_code);
return true;
}
}
return false;
}
// hostapd core functions accept "C" style function pointers, so use global
// functions to pass to the hostapd core function and store the corresponding
// std::function methods to be invoked.
//
// NOTE: Using the pattern from the vendor HAL (wifi_legacy_hal.cpp).
//
// Callback to be invoked once setup is complete
std::function<void(struct hostapd_data*)> on_setup_complete_internal_callback;
void onAsyncSetupCompleteCb(void* ctx)
{
struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
if (on_setup_complete_internal_callback) {
on_setup_complete_internal_callback(iface_hapd);
// Invalidate this callback since we don't want this firing
// again in single AP mode.
if (strlen(iface_hapd->conf->bridge) > 0) {
on_setup_complete_internal_callback = nullptr;
}
}
}
// Callback to be invoked on hotspot client connection/disconnection
std::function<void(struct hostapd_data*, const u8 *mac_addr, int authorized,
const u8 *p2p_dev_addr)> on_sta_authorized_internal_callback;
void onAsyncStaAuthorizedCb(void* ctx, const u8 *mac_addr, int authorized,
const u8 *p2p_dev_addr)
{
struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
if (on_sta_authorized_internal_callback) {
on_sta_authorized_internal_callback(iface_hapd, mac_addr,
authorized, p2p_dev_addr);
}
}
std::function<void(struct hostapd_data*, int level,
enum wpa_msg_type type, const char *txt,
size_t len)> on_wpa_msg_internal_callback;
void onAsyncWpaEventCb(void *ctx, int level,
enum wpa_msg_type type, const char *txt,
size_t len)
{
struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
if (on_wpa_msg_internal_callback) {
on_wpa_msg_internal_callback(iface_hapd, level,
type, txt, len);
}
}
inline ndk::ScopedAStatus createStatus(HostapdStatusCode status_code) {
return ndk::ScopedAStatus::fromServiceSpecificError(
static_cast<int32_t>(status_code));
}
inline ndk::ScopedAStatus createStatusWithMsg(
HostapdStatusCode status_code, std::string msg)
{
return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
static_cast<int32_t>(status_code), msg.c_str());
}
// Method called by death_notifier_ on client death.
void onDeath(void* cookie) {
wpa_printf(MSG_ERROR, "Client died. Terminating...");
eloop_terminate();
}
} // namespace
namespace aidl {
namespace android {
namespace hardware {
namespace wifi {
namespace hostapd {
Hostapd::Hostapd(struct hapd_interfaces* interfaces)
: interfaces_(interfaces)
{
death_notifier_ = AIBinder_DeathRecipient_new(onDeath);
}
::ndk::ScopedAStatus Hostapd::addAccessPoint(
const IfaceParams& iface_params, const NetworkParams& nw_params)
{
return addAccessPointInternal(iface_params, nw_params);
}
::ndk::ScopedAStatus Hostapd::removeAccessPoint(const std::string& iface_name)
{
return removeAccessPointInternal(iface_name);
}
::ndk::ScopedAStatus Hostapd::terminate()
{
wpa_printf(MSG_INFO, "Terminating...");
// Clear the callback to avoid IPCThreadState shutdown during the
// callback event.
callbacks_.clear();
eloop_terminate();
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus Hostapd::registerCallback(
const std::shared_ptr<IHostapdCallback>& callback)
{
return registerCallbackInternal(callback);
}
::ndk::ScopedAStatus Hostapd::forceClientDisconnect(
const std::string& iface_name, const std::vector<uint8_t>& client_address,
Ieee80211ReasonCode reason_code)
{
return forceClientDisconnectInternal(iface_name, client_address, reason_code);
}
::ndk::ScopedAStatus Hostapd::setDebugParams(DebugLevel level)
{
return setDebugParamsInternal(level);
}
::ndk::ScopedAStatus Hostapd::addAccessPointInternal(
const IfaceParams& iface_params,
const NetworkParams& nw_params)
{
int channelParamsSize = iface_params.channelParams.size();
if (channelParamsSize == 1) {
// Single AP
wpa_printf(MSG_INFO, "AddSingleAccessPoint, iface=%s",
iface_params.name.c_str());
return addSingleAccessPoint(iface_params, iface_params.channelParams[0],
nw_params, "", "");
} else if (channelParamsSize == 2) {
// Concurrent APs
wpa_printf(MSG_INFO, "AddDualAccessPoint, iface=%s",
iface_params.name.c_str());
return addConcurrentAccessPoints(iface_params, nw_params);
}
return createStatus(HostapdStatusCode::FAILURE_ARGS_INVALID);
}
std::vector<uint8_t> generateRandomOweSsid()
{
u8 random[8] = {0};
os_get_random(random, 8);
std::string ssid = StringPrintf("Owe-%s", random);
wpa_printf(MSG_INFO, "Generated OWE SSID: %s", ssid.c_str());
std::vector<uint8_t> vssid(ssid.begin(), ssid.end());
return vssid;
}
::ndk::ScopedAStatus Hostapd::addConcurrentAccessPoints(
const IfaceParams& iface_params, const NetworkParams& nw_params)
{
int channelParamsListSize = iface_params.channelParams.size();
// Get available interfaces in bridge
std::vector<std::string> managed_interfaces;
std::string br_name = StringPrintf(
"%s", iface_params.name.c_str());
if (!GetInterfacesInBridge(br_name, &managed_interfaces)) {
return createStatusWithMsg(HostapdStatusCode::FAILURE_UNKNOWN,
"Get interfaces in bridge failed.");
}
if (managed_interfaces.size() < channelParamsListSize) {
return createStatusWithMsg(HostapdStatusCode::FAILURE_UNKNOWN,
"Available interfaces less than requested bands");
}
// start BSS on specified bands
for (std::size_t i = 0; i < channelParamsListSize; i ++) {
IfaceParams iface_params_new = iface_params;
NetworkParams nw_params_new = nw_params;
iface_params_new.name = managed_interfaces[i];
std::string owe_transition_ifname = "";
if (nw_params.encryptionType == EncryptionType::WPA3_OWE_TRANSITION) {
if (i == 0 && i+1 < channelParamsListSize) {
owe_transition_ifname = managed_interfaces[i+1];
nw_params_new.encryptionType = EncryptionType::NONE;
} else {
owe_transition_ifname = managed_interfaces[0];
nw_params_new.isHidden = true;
nw_params_new.ssid = generateRandomOweSsid();
}
}
ndk::ScopedAStatus status = addSingleAccessPoint(
iface_params_new, iface_params.channelParams[i], nw_params_new,
br_name, owe_transition_ifname);
if (!status.isOk()) {
wpa_printf(MSG_ERROR, "Failed to addAccessPoint %s",
managed_interfaces[i].c_str());
return status;
}
}
// Save bridge interface info
br_interfaces_[br_name] = managed_interfaces;
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus Hostapd::addSingleAccessPoint(
const IfaceParams& iface_params,
const ChannelParams& channelParams,
const NetworkParams& nw_params,
const std::string br_name,
const std::string owe_transition_ifname)
{
if (hostapd_get_iface(interfaces_, iface_params.name.c_str())) {
wpa_printf(
MSG_ERROR, "Interface %s already present",
iface_params.name.c_str());
return createStatus(HostapdStatusCode::FAILURE_IFACE_EXISTS);
}
const auto conf_params = CreateHostapdConfig(iface_params, channelParams, nw_params,
br_name, owe_transition_ifname);
if (conf_params.empty()) {
wpa_printf(MSG_ERROR, "Failed to create config params");
return createStatus(HostapdStatusCode::FAILURE_ARGS_INVALID);
}
const auto conf_file_path =
WriteHostapdConfig(iface_params.name, conf_params);
if (conf_file_path.empty()) {
wpa_printf(MSG_ERROR, "Failed to write config file");
return createStatus(HostapdStatusCode::FAILURE_UNKNOWN);
}
std::string add_iface_param_str = StringPrintf(
"%s config=%s", iface_params.name.c_str(),
conf_file_path.c_str());
std::vector<char> add_iface_param_vec(
add_iface_param_str.begin(), add_iface_param_str.end() + 1);
if (hostapd_add_iface(interfaces_, add_iface_param_vec.data()) < 0) {
wpa_printf(
MSG_ERROR, "Adding interface %s failed",
add_iface_param_str.c_str());
return createStatus(HostapdStatusCode::FAILURE_UNKNOWN);
}
struct hostapd_data* iface_hapd =
hostapd_get_iface(interfaces_, iface_params.name.c_str());
WPA_ASSERT(iface_hapd != nullptr && iface_hapd->iface != nullptr);
// Register the setup complete callbacks
on_setup_complete_internal_callback =
[this](struct hostapd_data* iface_hapd) {
wpa_printf(
MSG_INFO, "AP interface setup completed - state %s",
hostapd_state_text(iface_hapd->iface->state));
if (iface_hapd->iface->state == HAPD_IFACE_DISABLED) {
// Invoke the failure callback on all registered
// clients.
for (const auto& callback : callbacks_) {
callback->onFailure(strlen(iface_hapd->conf->bridge) > 0 ?
iface_hapd->conf->bridge : iface_hapd->conf->iface,
iface_hapd->conf->iface);
}
}
};
// Register for new client connect/disconnect indication.
on_sta_authorized_internal_callback =
[this](struct hostapd_data* iface_hapd, const u8 *mac_addr,
int authorized, const u8 *p2p_dev_addr) {
wpa_printf(MSG_DEBUG, "notify client " MACSTR " %s",
MAC2STR(mac_addr),
(authorized) ? "Connected" : "Disconnected");
ClientInfo info;
info.ifaceName = strlen(iface_hapd->conf->bridge) > 0 ?
iface_hapd->conf->bridge : iface_hapd->conf->iface;
info.apIfaceInstance = iface_hapd->conf->iface;
info.clientAddress.assign(mac_addr, mac_addr + ETH_ALEN);
info.isConnected = authorized;
for (const auto &callback : callbacks_) {
callback->onConnectedClientsChanged(info);
}
};
// Register for wpa_event which used to get channel switch event
on_wpa_msg_internal_callback =
[this](struct hostapd_data* iface_hapd, int level,
enum wpa_msg_type type, const char *txt,
size_t len) {
wpa_printf(MSG_DEBUG, "Receive wpa msg : %s", txt);
if (os_strncmp(txt, AP_EVENT_ENABLED,
strlen(AP_EVENT_ENABLED)) == 0 ||
os_strncmp(txt, WPA_EVENT_CHANNEL_SWITCH,
strlen(WPA_EVENT_CHANNEL_SWITCH)) == 0) {
ApInfo info;
info.ifaceName = strlen(iface_hapd->conf->bridge) > 0 ?
iface_hapd->conf->bridge : iface_hapd->conf->iface,
info.apIfaceInstance = iface_hapd->conf->iface;
info.freqMhz = iface_hapd->iface->freq;
info.channelBandwidth = getChannelBandwidth(iface_hapd->iconf);
info.generation = getGeneration(iface_hapd->iface->current_mode);
info.apIfaceInstanceMacAddress.assign(iface_hapd->own_addr,
iface_hapd->own_addr + ETH_ALEN);
for (const auto &callback : callbacks_) {
callback->onApInstanceInfoChanged(info);
}
} else if (os_strncmp(txt, AP_EVENT_DISABLED, strlen(AP_EVENT_DISABLED)) == 0) {
// Invoke the failure callback on all registered clients.
for (const auto& callback : callbacks_) {
callback->onFailure(strlen(iface_hapd->conf->bridge) > 0 ?
iface_hapd->conf->bridge : iface_hapd->conf->iface,
iface_hapd->conf->iface);
}
}
};
// Setup callback
iface_hapd->setup_complete_cb = onAsyncSetupCompleteCb;
iface_hapd->setup_complete_cb_ctx = iface_hapd;
iface_hapd->sta_authorized_cb = onAsyncStaAuthorizedCb;
iface_hapd->sta_authorized_cb_ctx = iface_hapd;
wpa_msg_register_cb(onAsyncWpaEventCb);
if (hostapd_enable_iface(iface_hapd->iface) < 0) {
wpa_printf(
MSG_ERROR, "Enabling interface %s failed",
iface_params.name.c_str());
return createStatus(HostapdStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus Hostapd::removeAccessPointInternal(const std::string& iface_name)
{
// interfaces to be removed
std::vector<std::string> interfaces;
bool is_error = false;
const auto it = br_interfaces_.find(iface_name);
if (it != br_interfaces_.end()) {
// In case bridge, remove managed interfaces
interfaces = it->second;
br_interfaces_.erase(iface_name);
} else {
// else remove current interface
interfaces.push_back(iface_name);
}
for (auto& iface : interfaces) {
std::vector<char> remove_iface_param_vec(
iface.begin(), iface.end() + 1);
if (hostapd_remove_iface(interfaces_, remove_iface_param_vec.data()) < 0) {
wpa_printf(MSG_INFO, "Remove interface %s failed", iface.c_str());
is_error = true;
}
}
if (is_error) {
return createStatus(HostapdStatusCode::FAILURE_UNKNOWN);
}
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus Hostapd::registerCallbackInternal(
const std::shared_ptr<IHostapdCallback>& callback)
{
binder_status_t status = AIBinder_linkToDeath(callback->asBinder().get(),
death_notifier_, this /* cookie */);
if (status != STATUS_OK) {
wpa_printf(
MSG_ERROR,
"Error registering for death notification for "
"hostapd callback object");
return createStatus(HostapdStatusCode::FAILURE_UNKNOWN);
}
callbacks_.push_back(callback);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus Hostapd::forceClientDisconnectInternal(const std::string& iface_name,
const std::vector<uint8_t>& client_address, Ieee80211ReasonCode reason_code)
{
struct hostapd_data *hapd = hostapd_get_iface(interfaces_, iface_name.c_str());
bool result;
if (!hapd) {
for (auto const& iface : br_interfaces_) {
if (iface.first == iface_name) {
for (auto const& instance : iface.second) {
hapd = hostapd_get_iface(interfaces_, instance.c_str());
if (hapd) {
result = forceStaDisconnection(hapd, client_address,
(uint16_t) reason_code);
if (result) break;
}
}
}
}
} else {
result = forceStaDisconnection(hapd, client_address, (uint16_t) reason_code);
}
if (!hapd) {
wpa_printf(MSG_ERROR, "Interface %s doesn't exist", iface_name.c_str());
return createStatus(HostapdStatusCode::FAILURE_IFACE_UNKNOWN);
}
if (result) {
return ndk::ScopedAStatus::ok();
}
return createStatus(HostapdStatusCode::FAILURE_CLIENT_UNKNOWN);
}
::ndk::ScopedAStatus Hostapd::setDebugParamsInternal(DebugLevel level)
{
wpa_debug_level = static_cast<uint32_t>(level);
return ndk::ScopedAStatus::ok();
}
} // namespace hostapd
} // namespace wifi
} // namespace hardware
} // namespace android
} // namespace aidl