Merge "wifi: ignore SIGPIPE when dumping stats to dumpstate"
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index c7bfe08..a809a92 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -22,6 +22,8 @@
"libxml2",
],
shared_libs: [
+ "audioclient-types-aidl-unstable-cpp",
+ "libaudioclient_aidl_conversion",
"libbinder",
"libfmq",
],
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl
index 88c066c..a05fad9 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/AcquiredInfo.aidl
@@ -42,4 +42,8 @@
SENSOR_DIRTY = 21,
VENDOR = 22,
FIRST_FRAME_RECEIVED = 23,
+ DARK_GLASSES_DETECTED = 24,
+ FACE_COVERING_DETECTED = 25,
+ EYES_NOT_VISIBLE = 26,
+ MOUTH_NOT_VISIBLE = 27,
}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
index 5897cdc..56a600f 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
@@ -218,6 +218,30 @@
/**
* The first frame from the camera has been received.
*/
- FIRST_FRAME_RECEIVED = 23
+ FIRST_FRAME_RECEIVED = 23,
+
+ /**
+ * Dark glasses detected. This can be useful for providing relevant feedback to the user and
+ * enabling an alternative authentication logic if the implementation supports it.
+ */
+ DARK_GLASSES_DETECTED = 24,
+
+ /**
+ * A face mask or face covering detected. This can be useful for providing relevant feedback to
+ * the user and enabling an alternative authentication logic if the implementation supports it.
+ */
+ FACE_COVERING_DETECTED = 25,
+
+ /**
+ * Either one or both eyes are not visible in the frame. Prefer to use DARK_GLASSES_DETECTED if
+ * the eyes are not visible due to dark glasses.
+ */
+ EYES_NOT_VISIBLE = 26,
+
+ /**
+ * The mouth is not visible in the frame. Prefer to use MASK_DETECTED if the mouth is not
+ * visible due to a mask.
+ */
+ MOUTH_NOT_VISIBLE = 27,
}
diff --git a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Tag.aidl b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Tag.aidl
index fba58af..33a95fe 100644
--- a/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Tag.aidl
+++ b/keymint/aidl/aidl_api/android.hardware.keymint/current/android/hardware/keymint/Tag.aidl
@@ -41,7 +41,7 @@
MIN_SECONDS_BETWEEN_OPS = 805306771,
MAX_USES_PER_BOOT = 805306772,
USER_ID = 805306869,
- USER_SECURE_ID = 1073742326,
+ USER_SECURE_ID = -1610612234,
NO_AUTH_REQUIRED = 1879048695,
USER_AUTH_TYPE = 268435960,
AUTH_TIMEOUT = 805306873,
diff --git a/keymint/aidl/android/hardware/keymint/Tag.aidl b/keymint/aidl/android/hardware/keymint/Tag.aidl
index e85a8f5..46da096 100644
--- a/keymint/aidl/android/hardware/keymint/Tag.aidl
+++ b/keymint/aidl/android/hardware/keymint/Tag.aidl
@@ -355,7 +355,7 @@
*
* Must be hardware-enforced.
*/
- USER_SECURE_ID = (4 << 28) | 502, /* TagType:UINT_REP */
+ USER_SECURE_ID = (10 << 28) | 502, /* TagType:ULONG_REP */
/**
* Tag::NO_AUTH_REQUIRED specifies that no authentication is required to use this key. This tag
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
index bbd5343..a68830d 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Device.h
@@ -37,7 +37,6 @@
nn::GeneralResult<std::string> initVersionString(V1_2::IDevice* device);
nn::GeneralResult<nn::DeviceType> initDeviceType(V1_2::IDevice* device);
nn::GeneralResult<std::vector<nn::Extension>> initExtensions(V1_2::IDevice* device);
-nn::GeneralResult<nn::Capabilities> initCapabilities(V1_2::IDevice* device);
nn::GeneralResult<std::pair<uint32_t, uint32_t>> initNumberOfCacheFilesNeeded(
V1_2::IDevice* device);
diff --git a/neuralnetworks/1.2/utils/src/Device.cpp b/neuralnetworks/1.2/utils/src/Device.cpp
index 517d61f..a9e5377 100644
--- a/neuralnetworks/1.2/utils/src/Device.cpp
+++ b/neuralnetworks/1.2/utils/src/Device.cpp
@@ -42,6 +42,30 @@
#include <vector>
namespace android::hardware::neuralnetworks::V1_2::utils {
+namespace {
+
+nn::GeneralResult<nn::Capabilities> initCapabilities(V1_2::IDevice* device) {
+ CHECK(device != nullptr);
+
+ nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ const auto cb = [&result](V1_0::ErrorStatus status, const Capabilities& capabilities) {
+ if (status != V1_0::ErrorStatus::NONE) {
+ const auto canonical =
+ validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "getCapabilities_1_2 failed with " << toString(status);
+ } else {
+ result = validatedConvertToCanonical(capabilities);
+ }
+ };
+
+ const auto ret = device->getCapabilities_1_2(cb);
+ NN_TRY(hal::utils::handleTransportError(ret));
+
+ return result;
+}
+
+} // namespace
nn::GeneralResult<std::string> initVersionString(V1_2::IDevice* device) {
CHECK(device != nullptr);
@@ -106,27 +130,6 @@
return result;
}
-nn::GeneralResult<nn::Capabilities> initCapabilities(V1_2::IDevice* device) {
- CHECK(device != nullptr);
-
- nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
- << "uninitialized";
- const auto cb = [&result](V1_0::ErrorStatus status, const Capabilities& capabilities) {
- if (status != V1_0::ErrorStatus::NONE) {
- const auto canonical =
- validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
- result = NN_ERROR(canonical) << "getCapabilities_1_2 failed with " << toString(status);
- } else {
- result = validatedConvertToCanonical(capabilities);
- }
- };
-
- const auto ret = device->getCapabilities_1_2(cb);
- NN_TRY(hal::utils::handleTransportError(ret));
-
- return result;
-}
-
nn::GeneralResult<std::pair<uint32_t, uint32_t>> initNumberOfCacheFilesNeeded(
V1_2::IDevice* device) {
CHECK(device != nullptr);
diff --git a/neuralnetworks/1.3/utils/src/Device.cpp b/neuralnetworks/1.3/utils/src/Device.cpp
index 5e3d5c2..0fa244d 100644
--- a/neuralnetworks/1.3/utils/src/Device.cpp
+++ b/neuralnetworks/1.3/utils/src/Device.cpp
@@ -71,6 +71,27 @@
return NN_TRY(std::move(result));
}
+nn::GeneralResult<nn::Capabilities> initCapabilities(V1_3::IDevice* device) {
+ CHECK(device != nullptr);
+
+ nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "uninitialized";
+ const auto cb = [&result](ErrorStatus status, const Capabilities& capabilities) {
+ if (status != ErrorStatus::NONE) {
+ const auto canonical =
+ validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
+ result = NN_ERROR(canonical) << "getCapabilities_1_3 failed with " << toString(status);
+ } else {
+ result = validatedConvertToCanonical(capabilities);
+ }
+ };
+
+ const auto ret = device->getCapabilities_1_3(cb);
+ NN_TRY(hal::utils::handleTransportError(ret));
+
+ return result;
+}
+
} // namespace
nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name,
@@ -87,7 +108,7 @@
auto versionString = NN_TRY(V1_2::utils::initVersionString(device.get()));
const auto deviceType = NN_TRY(V1_2::utils::initDeviceType(device.get()));
auto extensions = NN_TRY(V1_2::utils::initExtensions(device.get()));
- auto capabilities = NN_TRY(V1_2::utils::initCapabilities(device.get()));
+ auto capabilities = NN_TRY(initCapabilities(device.get()));
const auto numberOfCacheFilesNeeded =
NN_TRY(V1_2::utils::initNumberOfCacheFilesNeeded(device.get()));
diff --git a/radio/1.6/IRadio.hal b/radio/1.6/IRadio.hal
index c73745a..dec247e 100644
--- a/radio/1.6/IRadio.hal
+++ b/radio/1.6/IRadio.hal
@@ -217,6 +217,13 @@
* Each subsequent request to this method is processed only after the
* completion of the previous one.
*
+ * When the SIM is in POWER_DOWN, the modem should send an empty vector of
+ * AppStatus in CardStatus.applications. If a SIM in the POWER_DOWN state
+ * is removed and a new SIM is inserted, the new SIM should be in POWER_UP
+ * mode by default. If the device is turned off or restarted while the SIM
+ * is in POWER_DOWN, then the SIM should turn on normally in POWER_UP mode
+ * when the device turns back on.
+ *
* Response callback is IRadioResponse.setSimCardPowerResponse_1_6().
* Note that this differs from setSimCardPower_1_1 in that the response
* callback should only be sent once the device has finished executing
diff --git a/radio/1.6/IRadioResponse.hal b/radio/1.6/IRadioResponse.hal
index c545db0..36e3ee4 100644
--- a/radio/1.6/IRadioResponse.hal
+++ b/radio/1.6/IRadioResponse.hal
@@ -207,7 +207,6 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_ARGUMENTS
* RadioError:SIM_ERR (indicates a timeout or other issue making the SIM unresponsive)
*
diff --git a/radio/1.6/types.hal b/radio/1.6/types.hal
index 2cba915..556d8a3 100644
--- a/radio/1.6/types.hal
+++ b/radio/1.6/types.hal
@@ -22,6 +22,7 @@
import @1.4::DataConnActiveStatus;
import @1.4::PdpProtocolType;
import @1.5::LinkAddress;
+
import android.hidl.safe_union@1.0::Monostate;
struct QosBandwidth {
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
index 6b1ff27..75772cd 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -321,7 +321,6 @@
res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::THROTTLE_ANCHOR_CARRIER,
60000);
ASSERT_OK(res);
-
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
@@ -351,7 +350,6 @@
res = radio_v1_6->setDataThrottling(serial, DataThrottlingAction::NO_DATA_THROTTLING, 60000);
ASSERT_OK(res);
-
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
@@ -361,4 +359,50 @@
::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
::android::hardware::radio::V1_6::RadioError::NONE,
::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS}));
-}
\ No newline at end of file
+}
+
+/*
+ * Test IRadio.setSimCardPower_1_6() for the response returned.
+ */
+TEST_P(RadioHidlTest_v1_6, setSimCardPower_1_6) {
+ /* Test setSimCardPower power down */
+ serial = GetRandomSerialNumber();
+ radio_v1_6->setSimCardPower_1_6(serial, CardPowerState::POWER_DOWN);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+ {::android::hardware::radio::V1_6::RadioError::NONE,
+ ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+ ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE}));
+
+ // setSimCardPower_1_6 does not return until the request is handled, and should not trigger
+ // CardState::ABSENT when turning off power
+ if (radioRsp_v1_6->rspInfo.error == ::android::hardware::radio::V1_6::RadioError::NONE) {
+ /* Wait some time for setting sim power down and then verify it */
+ updateSimCardStatus();
+ EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.base.cardState);
+ // applications should be an empty vector of AppStatus
+ EXPECT_EQ(0, cardStatus.applications.size());
+ }
+
+ /* Test setSimCardPower power up */
+ serial = GetRandomSerialNumber();
+ radio_v1_6->setSimCardPower_1_6(serial, CardPowerState::POWER_UP);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+ {::android::hardware::radio::V1_6::RadioError::NONE,
+ ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+ ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE}));
+
+ // setSimCardPower_1_6 does not return until the request is handled. Just verify that we still
+ // have CardState::PRESENT after turning the power back on
+ if (radioRsp_v1_6->rspInfo.error == ::android::hardware::radio::V1_6::RadioError::NONE) {
+ updateSimCardStatus();
+ EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.base.cardState);
+ }
+}
diff --git a/wifi/1.5/IWifiChip.hal b/wifi/1.5/IWifiChip.hal
index dcc9279..7cf81b5 100644
--- a/wifi/1.5/IWifiChip.hal
+++ b/wifi/1.5/IWifiChip.hal
@@ -17,6 +17,7 @@
package android.hardware.wifi@1.5;
import @1.0::WifiStatus;
+import @1.0::IWifiApIface;
import @1.0::IWifiIface;
import @1.3::IWifiChip;
import @1.4::IWifiChip;
@@ -127,4 +128,43 @@
* |WifiStatusCode.ERROR_INVALID_ARGS|
*/
setMultiStaUseCase(MultiStaUseCase useCase) generates (WifiStatus status);
+
+
+ /**
+ * Create bridged IWifiApIface.
+ *
+ * Depending on the mode the chip is configured in, the interface creation
+ * may fail (code: |ERROR_NOT_AVAILABLE|) if we've already reached the maximum
+ * allowed (specified in |ChipIfaceCombination|) number of ifaces of the AP
+ * type.
+ *
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|
+ * @return iface HIDL interface object representing the iface if
+ * successful, null otherwise.
+ */
+ createBridgedApIface() generates (WifiStatus status, IWifiApIface iface);
+
+ /**
+ * Removes one of the instance on the AP Iface with the provided ifaceName and
+ * ifaceInstanceName.
+ *
+ * Use the API: removeApIface with brIfaceName in the V1_0::WifiChip.hal to remove bridge Iface.
+ *
+ * @param brIfaceName Name of the bridged AP iface.
+ * @param ifaceInstanceName Name of the instance. The empty instance is
+ * invalid.
+ * @return status WifiStatus of the operation.
+ * Possible status codes:
+ * |WifiStatusCode.SUCCESS|,
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_INVALID_ARGS|,
+ * |WifiStatusCode.ERROR_NOT_AVAILABLE|
+ */
+ removeIfaceInstanceFromBridgedApIface(string brIfaceName, string ifaceInstanceName)
+ generates (WifiStatus status);
};
diff --git a/wifi/1.5/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
index 1c238c8..f5842fe 100644
--- a/wifi/1.5/default/wifi_chip.cpp
+++ b/wifi/1.5/default/wifi_chip.cpp
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <cutils/properties.h>
+#include <net/if.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
@@ -44,6 +45,7 @@
constexpr char kActiveWlanIfaceNameProperty[] = "wifi.active.interface";
constexpr char kNoActiveWlanIfaceNamePropertyValue[] = "";
constexpr unsigned kMaxWlanIfaces = 5;
+constexpr char kApBridgeIfacePrefix[] = "ap_br_";
template <typename Iface>
void invalidateAndClear(std::vector<sp<Iface>>& ifaces, sp<Iface> iface) {
@@ -434,6 +436,13 @@
&WifiChip::createApIfaceInternal, hidl_status_cb);
}
+Return<void> WifiChip::createBridgedApIface(
+ createBridgedApIface_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::createBridgedApIfaceInternal,
+ hidl_status_cb);
+}
+
Return<void> WifiChip::getApIfaceNames(getApIfaceNames_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::getApIfaceNamesInternal, hidl_status_cb);
@@ -453,6 +462,15 @@
ifname);
}
+Return<void> WifiChip::removeIfaceInstanceFromBridgedApIface(
+ const hidl_string& ifname, const hidl_string& ifInstanceName,
+ removeIfaceInstanceFromBridgedApIface_cb hidl_status_cb) {
+ return validateAndCall(
+ this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal,
+ hidl_status_cb, ifname, ifInstanceName);
+}
+
Return<void> WifiChip::createNanIface(createNanIface_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
&WifiChip::createNanIfaceInternal, hidl_status_cb);
@@ -693,6 +711,7 @@
}
void WifiChip::invalidateAndRemoveAllIfaces() {
+ invalidateAndClearBridgedApAll();
invalidateAndClearAll(ap_ifaces_);
invalidateAndClearAll(nan_ifaces_);
invalidateAndClearAll(p2p_ifaces_);
@@ -861,20 +880,20 @@
return {createWifiStatus(WifiStatusCode::SUCCESS), firmware_dump};
}
-std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::createApIfaceInternal() {
- if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
- return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
- }
- std::string ifname = allocateApIfaceName();
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->createVirtualInterface(
- ifname,
- hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP));
+WifiStatus WifiChip::createVirtualApInterface(const std::string& apVirtIf) {
+ legacy_hal::wifi_error legacy_status;
+ legacy_status = legacy_hal_.lock()->createVirtualInterface(
+ apVirtIf,
+ hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP));
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to add interface: " << ifname << " "
+ LOG(ERROR) << "Failed to add interface: " << apVirtIf << " "
<< legacyErrorToString(legacy_status);
- return {createWifiStatusFromLegacyError(legacy_status), {}};
+ return createWifiStatusFromLegacyError(legacy_status);
}
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+sp<WifiApIface> WifiChip::newWifiApIface(std::string& ifname) {
sp<WifiApIface> iface = new WifiApIface(ifname, legacy_hal_, iface_util_);
ap_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -883,6 +902,60 @@
}
}
setActiveWlanIfaceNameProperty(getFirstActiveWlanIfaceName());
+ return iface;
+}
+
+std::pair<WifiStatus, sp<IWifiApIface>> WifiChip::createApIfaceInternal() {
+ if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::string ifname = allocateApIfaceName();
+ WifiStatus status = createVirtualApInterface(ifname);
+ if (status.code != WifiStatusCode::SUCCESS) {
+ return {status, {}};
+ }
+ sp<WifiApIface> iface = newWifiApIface(ifname);
+ return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
+}
+
+std::pair<WifiStatus, sp<IWifiApIface>>
+WifiChip::createBridgedApIfaceInternal() {
+ if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::AP)) {
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ std::string br_ifname = kApBridgeIfacePrefix + allocateApIfaceName();
+ std::vector<std::string> ap_instances;
+ for (int i = 0; i < 2; i++) {
+ // TODO: b/173999527, it should use idx from 2 when STA+STA support, but
+ // need to check vendor support or not.
+ std::string ifaceInstanceName = allocateApOrStaIfaceName(
+ IfaceType::AP, isStaApConcurrencyAllowedInCurrentMode() ? 1 : 0);
+ WifiStatus status = createVirtualApInterface(ifaceInstanceName);
+ if (status.code != WifiStatusCode::SUCCESS) {
+ if (ap_instances.size() != 0) {
+ legacy_hal_.lock()->deleteVirtualInterface(
+ ap_instances.front());
+ }
+ return {status, {}};
+ }
+ ap_instances.push_back(ifaceInstanceName);
+ }
+ br_ifaces_ap_instances_[br_ifname] = ap_instances;
+ if (!iface_util_.lock()->createBridge(br_ifname)) {
+ LOG(ERROR) << "Failed createBridge - br_name=" << br_ifname.c_str();
+ invalidateAndClearBridgedAp(br_ifname);
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ for (auto const& instance : ap_instances) {
+ // Bind ap instance interface to AP bridge
+ if (!iface_util_.lock()->addIfaceToBridge(br_ifname, instance)) {
+ LOG(ERROR) << "Failed add if to Bridge - if_name="
+ << instance.c_str();
+ invalidateAndClearBridgedAp(br_ifname);
+ return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+ }
+ }
+ sp<WifiApIface> iface = newWifiApIface(br_ifname);
return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
}
@@ -913,12 +986,8 @@
// nan/rtt objects over AP iface. But, there is no harm to do it
// here and not make that assumption all over the place.
invalidateAndRemoveDependencies(ifname);
- legacy_hal::wifi_error legacy_status =
- legacy_hal_.lock()->deleteVirtualInterface(ifname);
- if (legacy_status != legacy_hal::WIFI_SUCCESS) {
- LOG(ERROR) << "Failed to remove interface: " << ifname << " "
- << legacyErrorToString(legacy_status);
- }
+ // Clear the bridge interface and the iface instance.
+ invalidateAndClearBridgedAp(ifname);
invalidateAndClear(ap_ifaces_, iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
@@ -929,6 +998,42 @@
return createWifiStatus(WifiStatusCode::SUCCESS);
}
+WifiStatus WifiChip::removeIfaceInstanceFromBridgedApIfaceInternal(
+ const std::string& ifname, const std::string& ifInstanceName) {
+ legacy_hal::wifi_error legacy_status;
+ const auto iface = findUsingName(ap_ifaces_, ifname);
+ if (!iface.get() || !ifInstanceName.empty()) {
+ return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+ }
+ // Requires to remove one of the instance in bridge mode
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == ifname) {
+ for (auto const& iface : it.second) {
+ if (iface == ifInstanceName) {
+ if (!iface_util_.lock()->removeIfaceFromBridge(it.first,
+ iface)) {
+ LOG(ERROR) << "Failed to remove interface: " << iface
+ << " from " << ifname << ", error: "
+ << legacyErrorToString(legacy_status);
+ return createWifiStatus(
+ WifiStatusCode::ERROR_NOT_AVAILABLE);
+ }
+ legacy_status =
+ legacy_hal_.lock()->deleteVirtualInterface(iface);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to del interface: " << iface
+ << " " << legacyErrorToString(legacy_status);
+ return createWifiStatusFromLegacyError(legacy_status);
+ }
+ }
+ }
+ break;
+ }
+ }
+ br_ifaces_ap_instances_.erase(ifInstanceName);
+ return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
std::pair<WifiStatus, sp<V1_4::IWifiNanIface>>
WifiChip::createNanIfaceInternal() {
if (!canCurrentModeSupportIfaceOfTypeWithCurrentIfaces(IfaceType::NAN)) {
@@ -1653,6 +1758,7 @@
uint32_t start_idx) {
for (unsigned idx = start_idx; idx < kMaxWlanIfaces; idx++) {
const auto ifname = getWlanIfaceNameWithType(type, idx);
+ if (findUsingNameFromBridgedApInstances(ifname)) continue;
if (findUsingName(ap_ifaces_, ifname)) continue;
if (findUsingName(sta_ifaces_, ifname)) continue;
return ifname;
@@ -1727,6 +1833,48 @@
return getWlanIfaceName(idx);
}
+void WifiChip::invalidateAndClearBridgedApAll() {
+ for (auto const& it : br_ifaces_ap_instances_) {
+ for (auto const& iface : it.second) {
+ iface_util_.lock()->removeIfaceFromBridge(it.first, iface);
+ legacy_hal_.lock()->deleteVirtualInterface(iface);
+ }
+ iface_util_.lock()->deleteBridge(it.first);
+ }
+ br_ifaces_ap_instances_.clear();
+}
+
+void WifiChip::invalidateAndClearBridgedAp(const std::string& br_name) {
+ if (br_name.empty()) return;
+ // delete managed interfaces
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == br_name) {
+ for (auto const& iface : it.second) {
+ iface_util_.lock()->removeIfaceFromBridge(br_name, iface);
+ legacy_hal_.lock()->deleteVirtualInterface(iface);
+ }
+ iface_util_.lock()->deleteBridge(br_name);
+ br_ifaces_ap_instances_.erase(br_name);
+ break;
+ }
+ }
+ return;
+}
+
+bool WifiChip::findUsingNameFromBridgedApInstances(const std::string& name) {
+ for (auto const& it : br_ifaces_ap_instances_) {
+ if (it.first == name) {
+ return true;
+ }
+ for (auto const& iface : it.second) {
+ if (iface == name) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
} // namespace implementation
} // namespace V1_5
} // namespace wifi
diff --git a/wifi/1.5/default/wifi_chip.h b/wifi/1.5/default/wifi_chip.h
index 693d480..b7a9ac8 100644
--- a/wifi/1.5/default/wifi_chip.h
+++ b/wifi/1.5/default/wifi_chip.h
@@ -94,11 +94,16 @@
Return<void> requestFirmwareDebugDump(
requestFirmwareDebugDump_cb hidl_status_cb) override;
Return<void> createApIface(createApIface_cb hidl_status_cb) override;
+ Return<void> createBridgedApIface(
+ createBridgedApIface_cb hidl_status_cb) override;
Return<void> getApIfaceNames(getApIfaceNames_cb hidl_status_cb) override;
Return<void> getApIface(const hidl_string& ifname,
getApIface_cb hidl_status_cb) override;
Return<void> removeApIface(const hidl_string& ifname,
removeApIface_cb hidl_status_cb) override;
+ Return<void> removeIfaceInstanceFromBridgedApIface(
+ const hidl_string& brIfaceName, const hidl_string& ifaceInstanceName,
+ removeIfaceInstanceFromBridgedApIface_cb hidl_status_cb) override;
Return<void> createNanIface(createNanIface_cb hidl_status_cb) override;
Return<void> getNanIfaceNames(getNanIfaceNames_cb hidl_status_cb) override;
Return<void> getNanIface(const hidl_string& ifname,
@@ -192,11 +197,16 @@
requestDriverDebugDumpInternal();
std::pair<WifiStatus, std::vector<uint8_t>>
requestFirmwareDebugDumpInternal();
+ sp<WifiApIface> newWifiApIface(std::string& ifname);
+ WifiStatus createVirtualApInterface(const std::string& apVirtIf);
std::pair<WifiStatus, sp<IWifiApIface>> createApIfaceInternal();
+ std::pair<WifiStatus, sp<IWifiApIface>> createBridgedApIfaceInternal();
std::pair<WifiStatus, std::vector<hidl_string>> getApIfaceNamesInternal();
std::pair<WifiStatus, sp<IWifiApIface>> getApIfaceInternal(
const std::string& ifname);
WifiStatus removeApIfaceInternal(const std::string& ifname);
+ WifiStatus removeIfaceInstanceFromBridgedApIfaceInternal(
+ const std::string& brIfaceName, const std::string& ifInstanceName);
std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> createNanIfaceInternal();
std::pair<WifiStatus, std::vector<hidl_string>> getNanIfaceNamesInternal();
std::pair<WifiStatus, sp<V1_4::IWifiNanIface>> getNanIfaceInternal(
@@ -272,6 +282,9 @@
std::string allocateStaIfaceName();
bool writeRingbufferFilesInternal();
std::string getWlanIfaceNameWithType(IfaceType type, unsigned idx);
+ void invalidateAndClearBridgedApAll();
+ void invalidateAndClearBridgedAp(const std::string& br_name);
+ bool findUsingNameFromBridgedApInstances(const std::string& name);
ChipId chip_id_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
@@ -296,7 +309,7 @@
event_cb_handler_;
const std::function<void(const std::string&)> subsystemCallbackHandler_;
-
+ std::map<std::string, std::vector<std::string>> br_ifaces_ap_instances_;
DISALLOW_COPY_AND_ASSIGN(WifiChip);
};
diff --git a/wifi/supplicant/1.4/ISupplicantStaIface.hal b/wifi/supplicant/1.4/ISupplicantStaIface.hal
index f9e4c9b..7441ba5 100644
--- a/wifi/supplicant/1.4/ISupplicantStaIface.hal
+++ b/wifi/supplicant/1.4/ISupplicantStaIface.hal
@@ -71,8 +71,7 @@
* |SupplicantStatusCode.FAILURE_UNKNOWN|,
* |SupplicantStatusCode.FAILURE_IFACE_INVALID|
*/
- initiateVenueUrlAnqpQuery(MacAddress macAddress)
- generates (SupplicantStatus status);
+ initiateVenueUrlAnqpQuery(MacAddress macAddress) generates (SupplicantStatus status);
/**
* Get wpa driver capabilities.
@@ -84,4 +83,55 @@
*/
getWpaDriverCapabilities_1_4() generates (SupplicantStatus status,
bitfield<WpaDriverCapabilitiesMask> driverCapabilitiesMask);
+
+ /**
+ * Generates DPP bootstrap information: Bootstrap ID, DPP URI and listen
+ * channel for responder mode.
+ *
+ * @param MacAddress MAC address of the interface for the DPP operation.
+ * @param deviceInfo Device specific information.
+ * As per DPP Specification V1.0 section 5.2,
+ * allowed Range of ASCII characters in deviceInfo - %x20-7E
+ * semicolon is not allowed.
+ * @param DppCurve Elliptic curve cryptography type used to generate DPP
+ * public/private key pair.
+ * @return status of operation and bootstrap info.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_IFACE_INVALID|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ * |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+ */
+ generateDppBootstrapInfoForResponder(MacAddress macAddress, string deviceInfo, DppCurve curve)
+ generates (SupplicantStatus status, DppResponderBootstrapInfo bootstrapInfo);
+
+ /**
+ * Start DPP in Enrollee-Responder mode.
+ * Framework must first call |generateDppBootstrapInfoForResponder| to generate
+ * the bootstrapping information: Bootstrap ID, DPP URI and the listen channel.
+ * Then call this API with derived listen channel to start listening for
+ * authentication request from Peer initiator.
+ *
+ * @param listenChannel DPP listen channel.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|,
+ * |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+ * |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+ */
+ startDppEnrolleeResponder(uint32_t listenChannel) generates (SupplicantStatus status);
+
+ /**
+ * Stop DPP Responder operation - Remove the bootstrap code and stop listening.
+ *
+ * @param ownBootstrapId Local device's URI ID obtained through
+ * |generateDppBootstrapInfoForResponder| call.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_IFACE_INVALID|
+ * |SupplicantStatusCode.FAILURE_UNSUPPORTED|
+ */
+ stopDppResponder(uint32_t ownBootstrapId) generates (SupplicantStatus status);
};
diff --git a/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.hal b/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.hal
index 852696d..efcebda 100644
--- a/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.hal
+++ b/wifi/supplicant/1.4/ISupplicantStaIfaceCallback.hal
@@ -40,8 +40,12 @@
/**
* Baseline information as defined in HAL 1.0.
*/
- @1.0::ISupplicantStaIfaceCallback.AnqpData V1_0; /* Container for v1.0 of this struct */
- vec<uint8_t> venueUrl; /* Venue URL ANQP-element */
+ @1.0::ISupplicantStaIfaceCallback.AnqpData V1_0;
+
+ /*
+ * Container for v1.0 of this struct
+ */
+ vec<uint8_t> venueUrl;
};
/**
diff --git a/wifi/supplicant/1.4/ISupplicantStaNetwork.hal b/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
index 80beedf..6bed5ab 100644
--- a/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
+++ b/wifi/supplicant/1.4/ISupplicantStaNetwork.hal
@@ -17,7 +17,7 @@
package android.hardware.wifi.supplicant@1.4;
import @1.3::ISupplicantStaNetwork;
-import @1.4::ISupplicantStaNetworkCallback;
+import ISupplicantStaNetworkCallback;
/**
* Interface exposed by the supplicant for each station mode network
diff --git a/wifi/supplicant/1.4/types.hal b/wifi/supplicant/1.4/types.hal
index 18af8fe..aec61c4 100644
--- a/wifi/supplicant/1.4/types.hal
+++ b/wifi/supplicant/1.4/types.hal
@@ -18,6 +18,7 @@
import @1.0::SupplicantStatusCode;
import @1.3::ConnectionCapabilities;
+import @1.3::DppFailureCode;
import @1.3::WpaDriverCapabilitiesMask;
/**
@@ -40,6 +41,29 @@
};
/**
+ * DppFailureCode: Error codes for DPP (Easy Connect)
+ */
+enum DppFailureCode : @1.3::DppFailureCode {
+ /**
+ * Failure to generate a DPP URI.
+ */
+ URI_GENERATION,
+};
+
+/**
+ * DppCurve: Elliptic curve cryptography type used to generate DPP
+ * public/private key pair.
+ */
+enum DppCurve : uint32_t {
+ PRIME256V1,
+ SECP384R1,
+ SECP521R1,
+ BRAINPOOLP256R1,
+ BRAINPOOLP384R1,
+ BRAINPOOLP512R1,
+};
+
+/**
* Connection Capabilities supported by current network and device
*/
struct ConnectionCapabilities {
@@ -47,6 +71,7 @@
* Baseline information as defined in HAL 1.3.
*/
@1.3::ConnectionCapabilities V1_3;
+
/**
* detailed network mode for legacy network
*/
@@ -64,13 +89,14 @@
* Generic structure to return the status of any supplicant operation.
*/
struct SupplicantStatus {
- SupplicantStatusCode code;
- /**
- * A vendor specific error message to provide more information beyond the
- * status code.
- * This will be used for debbuging purposes only.
- */
- string debugMessage;
+ SupplicantStatusCode code;
+
+ /**
+ * A vendor specific error message to provide more information beyond the
+ * status code.
+ * This will be used for debbuging purposes only.
+ */
+ string debugMessage;
};
/**
@@ -78,7 +104,27 @@
*/
enum WpaDriverCapabilitiesMask : @1.3::WpaDriverCapabilitiesMask {
/**
- *
*/
SAE_PK = 1 << 2,
};
+
+/**
+ * DPP bootstrap info generated for responder mode operation
+ */
+struct DppResponderBootstrapInfo {
+ /**
+ * Generated bootstrap identifier
+ */
+ uint32_t bootstrapId;
+
+ /**
+ * The Wi-Fi channel that the DPP responder is listening on.
+ */
+ uint32_t listenChannel;
+
+ /**
+ * Bootstrapping URI per DPP specification, "section 5.2 Bootstrapping
+ * information", may contain listen channel, MAC address, public key, or other information.
+ */
+ string uri;
+};
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp
index c0b5a70..ccd469d 100644
--- a/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -19,6 +19,7 @@
#include <android/hardware/wifi/supplicant/1.1/ISupplicant.h>
#include <android/hardware/wifi/supplicant/1.2/types.h>
#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
#include <android/hardware/wifi/supplicant/1.3/types.h>
#include <android/hardware/wifi/supplicant/1.4/ISupplicant.h>
#include <android/hardware/wifi/supplicant/1.4/ISupplicantStaIface.h>
@@ -45,7 +46,10 @@
using ::android::hardware::wifi::supplicant::V1_2::DppNetRole;
using ::android::hardware::wifi::supplicant::V1_2::DppProgressCode;
using ::android::hardware::wifi::supplicant::V1_3::DppSuccessCode;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
using ::android::hardware::wifi::supplicant::V1_4::ConnectionCapabilities;
+using ::android::hardware::wifi::supplicant::V1_4::DppCurve;
+using ::android::hardware::wifi::supplicant::V1_4::DppResponderBootstrapInfo;
using ::android::hardware::wifi::supplicant::V1_4::ISupplicant;
using ::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIface;
using ::android::hardware::wifi::supplicant::V1_4::ISupplicantStaIfaceCallback;
@@ -74,6 +78,24 @@
sp<ISupplicantStaIface> sta_iface_;
// MAC address to use for various tests.
std::array<uint8_t, 6> mac_addr_;
+
+ bool isDppSupported() {
+ uint32_t keyMgmtMask = 0;
+
+ // We need to first get the key management capabilities from the device.
+ // If DPP is not supported, we just pass the test.
+ sta_iface_->getKeyMgmtCapabilities_1_3(
+ [&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ keyMgmtMask = keyMgmtMaskInternal;
+ });
+
+ if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::DPP)) {
+ // DPP not supported
+ return false;
+ }
+ return true;
+ }
};
class IfaceCallback : public ISupplicantStaIfaceCallback {
@@ -255,6 +277,48 @@
});
}
+/*
+ * StartDppEnrolleeResponder
+ */
+TEST_P(SupplicantStaIfaceHidlTest, StartDppEnrolleeResponder) {
+ // We need to first get the key management capabilities from the device.
+ // If DPP is not supported, we just pass the test.
+ if (!isDppSupported()) {
+ // DPP not supported
+ return;
+ }
+
+ hidl_string deviceInfo = "DPP_Responder_Mode_VTS_Test";
+ uint32_t bootstrap_id = 0;
+ uint32_t listen_channel = 0;
+ uint8_t mac_address[6] = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+
+ // Generate DPP bootstrap information
+ sta_iface_->generateDppBootstrapInfoForResponder(
+ mac_address, deviceInfo, DppCurve::PRIME256V1,
+ [&](const SupplicantStatusV1_4& status,
+ DppResponderBootstrapInfo bootstrapInfo) {
+ EXPECT_EQ(SupplicantStatusCodeV1_4::SUCCESS, status.code);
+ EXPECT_NE(-1, bootstrapInfo.bootstrapId);
+ EXPECT_NE(0, bootstrapInfo.bootstrapId);
+ bootstrap_id = bootstrapInfo.bootstrapId;
+ listen_channel = bootstrapInfo.listenChannel;
+ EXPECT_NE(0, bootstrapInfo.listenChannel);
+ });
+
+ // Start DPP as Enrollee-Responder.
+ sta_iface_->startDppEnrolleeResponder(
+ listen_channel, [&](const SupplicantStatusV1_4& status) {
+ EXPECT_EQ(SupplicantStatusCodeV1_4::SUCCESS, status.code);
+ });
+
+ // Stop DPP Enrollee-Responder mode, ie remove the URI and stop listen.
+ sta_iface_->stopDppResponder(
+ bootstrap_id, [&](const SupplicantStatusV1_4& status) {
+ EXPECT_EQ(SupplicantStatusCodeV1_4::SUCCESS, status.code);
+ });
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaIfaceHidlTest);
INSTANTIATE_TEST_CASE_P(
PerInstance, SupplicantStaIfaceHidlTest,