wifi: Create 1.3::IfaceParams to support dual bands (AP+AP Part 1)
1. Use 1.3::IfaceParams to support AP+AP.
The design still uses 1.2::IfaceParams to create the AP but it updates
1.2::IfaceParams from 1.3::IfaceParams since dual APs information are stored
in 1.3::IfaceParams.
a. Support interface query from bridge interface.
b. Read dual APs configuration adn enable it.
c. Callback use bridge interface in dual APs mode.
AP+AP Part 1 includes:
1. HIDL: Hostapd support dual bands/channels configuration
2. Framework: HostapdHal support only
3. Hostapd deamon:
a. Support briged interface
b. Support config dual bands/channel
c. Callback use bridge interface in dual APs mode.
Bug: 162686273
Test: Manual Test to test single AP mode.
Test: Manual test code to check hostapd.conf is expected.
Test: atest -c VtsHalWifiHostapdV1_3TargetTest
Test: atest -c VtsHalWifiHostapdV1_2TargetTest
Test: atest -c VtsHalWifiHostapdV1_1TargetTest
Test: atest -c VtsHalWifiHostapdV1_0TargetTest
Change-Id: I7d2a0ae1f935a18dd62daa3befc0eae0452882cc
diff --git a/hostapd/hidl/1.3/hostapd.cpp b/hostapd/hidl/1.3/hostapd.cpp
index 668d8f4..6bbf3d9 100644
--- a/hostapd/hidl/1.3/hostapd.cpp
+++ b/hostapd/hidl/1.3/hostapd.cpp
@@ -10,9 +10,14 @@
#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 "hidl_return_util.h"
@@ -20,6 +25,7 @@
extern "C"
{
#include "common/wpa_ctrl.h"
+#include "drivers/linux_ioctl.h"
}
// The HIDL implementation for hostapd creates a hostapd.conf dynamically for
@@ -37,6 +43,46 @@
using android::hardware::wifi::hostapd::V1_3::Generation;
using android::hardware::wifi::hostapd::V1_3::Bandwidth;
+#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)
{
@@ -217,8 +263,9 @@
}
std::string CreateHostapdConfig(
- const IHostapd::IfaceParams& iface_params,
- const IHostapd::NetworkParams& nw_params)
+ const android::hardware::wifi::hostapd::V1_2::IHostapd::IfaceParams& iface_params,
+ const IHostapd::NetworkParams& nw_params,
+ const std::string br_name)
{
if (nw_params.V1_2.V1_0.ssid.size() >
static_cast<uint32_t>(
@@ -412,6 +459,11 @@
}
#endif /* CONFIG_INTERWORKING */
+ std::string bridge_as_string;
+ if (!br_name.empty()) {
+ bridge_as_string = StringPrintf("bridge=%s", br_name.c_str());
+ }
+
return StringPrintf(
"interface=%s\n"
"driver=nl80211\n"
@@ -431,6 +483,7 @@
#ifdef CONFIG_INTERWORKING
"%s\n"
#endif /* CONFIG_INTERWORKING */
+ "%s\n"
"%s\n",
iface_params.V1_1.V1_0.ifaceName.c_str(), ssid_as_string.c_str(),
channel_config_as_string.c_str(),
@@ -440,9 +493,10 @@
hw_mode_as_string.c_str(), ht_cap_vht_oper_chwidth_as_string.c_str(),
nw_params.V1_2.V1_0.isHidden ? 1 : 0,
#ifdef CONFIG_INTERWORKING
- access_network_params_as_string.c_str(),
+ access_network_params_as_string.c_str(),
#endif /* CONFIG_INTERWORKING */
- encryption_config_as_string.c_str());
+ encryption_config_as_string.c_str(),
+ bridge_as_string.c_str());
}
Generation getGeneration(hostapd_hw_modes *current_mode)
@@ -504,8 +558,10 @@
if (on_setup_complete_internal_callback) {
on_setup_complete_internal_callback(iface_hapd);
// Invalidate this callback since we don't want this firing
- // again.
- on_setup_complete_internal_callback = nullptr;
+ // again in single AP mode.
+ if (strlen(iface_hapd->conf->bridge) > 0) {
+ on_setup_complete_internal_callback = nullptr;
+ }
}
}
@@ -655,17 +711,89 @@
return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN, ""};
}
+V1_2::IHostapd::IfaceParams prepareIfaceParams1_2From1_3(const std::string interfaceName,
+ const V1_3::IHostapd::IfaceParams iface_1_3,
+ const V1_3::IHostapd::ChannelParams channelParams_1_3)
+{
+ // Using HIDL 1.2 iface_params to enable the AP
+ V1_2::IHostapd::IfaceParams iface_params_1_2 = iface_1_3.V1_2;
+ iface_params_1_2.V1_1.V1_0.ifaceName = interfaceName;
+ // Prepare bandMask & acsChannelFreqRangesMhz
+ iface_params_1_2.channelParams = channelParams_1_3.V1_2;
+ // Prepare channel
+ iface_params_1_2.V1_1.V1_0.channelParams.channel = channelParams_1_3.channel;
+ // Prepare enableAcs
+ iface_params_1_2.V1_1.V1_0.channelParams.enableAcs = channelParams_1_3.enableAcs;
+ return iface_params_1_2;
+}
+
V1_2::HostapdStatus Hostapd::addAccessPointInternal_1_3(
- const V1_2::IHostapd::IfaceParams& iface_params,
+ const V1_3::IHostapd::IfaceParams& iface_params,
const V1_3::IHostapd::NetworkParams& nw_params)
{
+ int channelParamsListSize = iface_params.channelParamsList.size();
+ if (channelParamsListSize == 1) {
+ // Single AP
+ wpa_printf(MSG_INFO, "AddSingleAccessPoint, iface=%s",
+ iface_params.V1_2.V1_1.V1_0.ifaceName.c_str());
+ return addSingleAccessPoint(
+ prepareIfaceParams1_2From1_3(iface_params.V1_2.V1_1.V1_0.ifaceName,
+ iface_params, iface_params.channelParamsList[0]),
+ nw_params, "");
+ } else if (channelParamsListSize == 2) {
+ // Concurrent APs
+ wpa_printf(MSG_INFO, "AddDualAccessPoint, iface=%s",
+ iface_params.V1_2.V1_1.V1_0.ifaceName.c_str());
+ return addConcurrentAccessPoints(iface_params, nw_params);
+ }
+ return {V1_2::HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
+}
+
+V1_2::HostapdStatus Hostapd::addConcurrentAccessPoints(
+ const V1_3::IHostapd::IfaceParams& iface_params, const V1_3::IHostapd::NetworkParams& nw_params)
+{
+ int channelParamsListSize = iface_params.channelParamsList.size();
+ // Get available interfaces in bridge
+ std::vector<std::string> managed_interfaces;
+ std::string br_name = StringPrintf(
+ "%s", iface_params.V1_2.V1_1.V1_0.ifaceName.c_str());
+ if (!GetInterfacesInBridge(br_name, &managed_interfaces)) {
+ return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN,
+ "Get interfaces in bridge failed."};
+ }
+ if (managed_interfaces.size() < channelParamsListSize) {
+ return {V1_2::HostapdStatusCode::FAILURE_UNKNOWN,
+ "Available interfaces less than requested bands"};
+ }
+ // start BSS on specified bands
+ for (std::size_t i = 0; i < channelParamsListSize; i ++) {
+ V1_2::HostapdStatus status = addSingleAccessPoint(
+ prepareIfaceParams1_2From1_3(managed_interfaces[i], iface_params,
+ iface_params.channelParamsList[i]),
+ nw_params, br_name);
+ if (status.code != V1_2::HostapdStatusCode::SUCCESS) {
+ 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 {V1_2::HostapdStatusCode::SUCCESS, ""};
+}
+
+V1_2::HostapdStatus Hostapd::addSingleAccessPoint(
+ const V1_2::IHostapd::IfaceParams& iface_params,
+ const V1_3::IHostapd::NetworkParams& nw_params,
+ const std::string br_name)
+{
if (hostapd_get_iface(interfaces_, iface_params.V1_1.V1_0.ifaceName.c_str())) {
wpa_printf(
MSG_ERROR, "Interface %s already present",
iface_params.V1_1.V1_0.ifaceName.c_str());
return {V1_2::HostapdStatusCode::FAILURE_IFACE_EXISTS, ""};
}
- const auto conf_params = CreateHostapdConfig(iface_params, nw_params);
+ const auto conf_params = CreateHostapdConfig(iface_params, nw_params, br_name);
if (conf_params.empty()) {
wpa_printf(MSG_ERROR, "Failed to create config params");
return {V1_2::HostapdStatusCode::FAILURE_ARGS_INVALID, ""};
@@ -694,7 +822,7 @@
on_setup_complete_internal_callback =
[this](struct hostapd_data* iface_hapd) {
wpa_printf(
- MSG_DEBUG, "AP interface setup completed - state %s",
+ 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
@@ -713,11 +841,9 @@
wpa_printf(MSG_DEBUG, "notify client " MACSTR " %s",
MAC2STR(mac_addr),
(authorized) ? "Connected" : "Disconnected");
-
for (const auto &callback : callbacks_) {
- // TODO: The iface need to separate to iface and ap instance
- // identify for AP+AP case.
- callback->onConnectedClientsChanged(iface_hapd->conf->iface,
+ callback->onConnectedClientsChanged(strlen(iface_hapd->conf->bridge) > 0 ?
+ iface_hapd->conf->bridge : iface_hapd->conf->iface,
iface_hapd->conf->iface, mac_addr, authorized);
}
};
@@ -732,8 +858,10 @@
strlen(WPA_EVENT_CHANNEL_SWITCH)) == 0) {
for (const auto &callback : callbacks_) {
callback->onApInstanceInfoChanged(
- iface_hapd->conf->iface, iface_hapd->conf->iface,
- iface_hapd->iface->freq, getBandwidth(iface_hapd->iconf),
+ strlen(iface_hapd->conf->bridge) > 0 ?
+ iface_hapd->conf->bridge : iface_hapd->conf->iface,
+ iface_hapd->conf->iface, iface_hapd->iface->freq,
+ getBandwidth(iface_hapd->iconf),
getGeneration(iface_hapd->iface->current_mode),
iface_hapd->own_addr);
}
diff --git a/hostapd/hidl/1.3/hostapd.h b/hostapd/hidl/1.3/hostapd.h
index 79354d3..ceec080 100644
--- a/hostapd/hidl/1.3/hostapd.h
+++ b/hostapd/hidl/1.3/hostapd.h
@@ -71,7 +71,7 @@
const V1_2::IHostapd::NetworkParams& nw_params,
addAccessPoint_1_2_cb _hidl_cb) override;
Return<void> addAccessPoint_1_3(
- const V1_2::IHostapd::IfaceParams& iface_params,
+ const V1_3::IHostapd::IfaceParams& iface_params,
const V1_3::IHostapd::NetworkParams& nw_params,
addAccessPoint_1_3_cb _hidl_cb) override;
Return<void> removeAccessPoint(
@@ -102,7 +102,14 @@
const V1_2::IHostapd::IfaceParams& IfaceParams,
const V1_2::IHostapd::NetworkParams& nw_params);
V1_2::HostapdStatus addAccessPointInternal_1_3(
+ const V1_3::IHostapd::IfaceParams& IfaceParams,
+ const V1_3::IHostapd::NetworkParams& nw_params);
+ V1_2::HostapdStatus addSingleAccessPoint(
const V1_2::IHostapd::IfaceParams& IfaceParams,
+ const V1_3::IHostapd::NetworkParams& nw_params,
+ std::string br_name);
+ V1_2::HostapdStatus addConcurrentAccessPoints(
+ const V1_3::IHostapd::IfaceParams& IfaceParams,
const V1_3::IHostapd::NetworkParams& nw_params);
V1_0::HostapdStatus removeAccessPointInternal(const std::string& iface_name);
V1_0::HostapdStatus registerCallbackInternal(
@@ -120,6 +127,8 @@
std::vector<sp<V1_3::IHostapdCallback>> callbacks_;
// Death notifier.
android::sp<DeathNotifier> death_notifier_;
+ // Bridge and its managed interfaces.
+ std::map<std::string, std::vector<std::string>> br_interfaces_;
DISALLOW_COPY_AND_ASSIGN(Hostapd);
};
} // namespace implementation